一、问题描述
希望修改请求中的Header/Cookies。
二、环境
语言:java
项目脚手架:springboot
三、解决方式
1、基于反射(需要在InterceptorRegistry注入我们写的bean)
1.1 修改 Cookies
import org.apache.catalina.connector.RequestFacade;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
/**
* @author chen-biao
* @Date 2021/6/8 17:13
*/
public class ManagerAutoLoginInterceptor extends HandlerInterceptorAdapter {
private static final Logger logger = LoggerFactory.getLogger(ManagerAutoLoginInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//调试发现,通过 postMan 发送的请求,request对应的实现类为: RequestFacade
if (!(request instanceof RequestFacade)) {
return true;
}
Field cookiesField = null;
Request cookieRequest = null;
RequestFacade rf = (RequestFacade) request;
Class requestClass = rf.getClass();
Field requestField = null;
try {
requestField = requestClass.getDeclaredField("request");
} catch (Exception e) {
logger.info("request is null.");
return true;
}
requestField.setAccessible(true);
Object requestObject = requestField.get(rf);
if (requestObject instanceof Request) {
cookieRequest = (Request) requestObject;
requestClass = cookieRequest.getClass();
try {
cookiesField = requestClass.getDeclaredField("cookies");
} catch (Exception e) {
logger.info("Request cookiesField is null.");
return true;
}
}
if (null == cookiesField) {
logger.error("auto-login:获取不到cookies,无法完成反射设值。");
return true;
}
cookiesField.setAccessible(true);
Cookie[] cookies = new Cookie[1];
Cookie cookie = new Cookie("你希望设置的cookie key", "你希望设置的cookie value");
cookies[0] = cookie;
cookiesField.set(cookieRequest, cookies);
logger.info("auto-login-end:自动设置请求token完成。");
return true;
}
}
1.2 修改 Header
import com.berchina.platform.security.SecurityContanst;
import org.apache.catalina.connector.RequestFacade;
import org.apache.tomcat.util.buf.MessageBytes;
import org.apache.tomcat.util.http.MimeHeaders;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
/**
* @author chen-biao
* @Date 2021/6/8 18:13
*/
public class MobileAutoLoginInterceptor extends HandlerInterceptorAdapter {
private static final Logger logger = LoggerFactory.getLogger(MobileAutoLoginInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (!(request instanceof RequestFacade)) {
return true;
}
String httpToken = request.getHeader(SecurityContanst.USER_TOKEN_NAME);
if (null != httpToken) {
logger.info("auto-login:带有token,使用自带token进行后续操作。token: {}", httpToken);
return true;
}
String headerName = "你希望这是的header名称";
String headerValue = "你希望设置的header值";
Class<? extends HttpServletRequest> requestClass = request.getClass();
try {
Field request1 = requestClass.getDeclaredField("request");
request1.setAccessible(true);
Object o = request1.get(request);
Field coyoteRequest = o.getClass().getDeclaredField("coyoteRequest");
coyoteRequest.setAccessible(true);
Object o1 = coyoteRequest.get(o);
Field headers = o1.getClass().getDeclaredField("headers");
headers.setAccessible(true);
MimeHeaders o2 = (MimeHeaders) headers.get(o1);
o2.addValue(headerName);
Field mimeHeadersHeaders = o2.getClass().getDeclaredField("headers");
mimeHeadersHeaders.setAccessible(true);
Object[] o3 = (Object[]) mimeHeadersHeaders.get(o2);
for (Object om : o3) {
Field nameBField = om.getClass().getDeclaredField("nameB");
nameBField.setAccessible(true);
MessageBytes nameB = (MessageBytes) nameBField.get(om);
if (headerName.equals(nameB.getString())) {
Field valueBField = om.getClass().getDeclaredField("valueB");
valueBField.setAccessible(true);
MessageBytes valueB = MessageBytes.newInstance();
valueB.setString(headerValue);
valueBField.set(om, valueB);
logger.info("auto-login:设置的token:{}",headerValue );
}
}
} catch (Exception e) {
logger.error("auto-login:set token error.", e);
return true;
}
logger.info("auto-login-end:自动设置请求token完成。");
return true;
}
}
2、基于代理模式 (通过注解:Component,ConditionalOnProperty,Configuration 可以做到代码无侵入)
import javax.servlet.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.IOException;
import java.util.Arrays;
/**
* @author chen-biao
* @Date 2021/6/9 8:23
*/
@Component
public class MobileAutoLoginFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
String headerName = "你希望设置的header名称";
String headerValue = "header值";
String cookiesName = "cookies名称";
String cookiesValue = "cookies值";
HttpServletRequestWrapper requestWrapper = new HttpServletRequestWrapper((HttpServletRequest) request) {
/**
* 当调用request.getHeader("token")时,则获取请求参数中token值并当做Header的值返回
*/
@Override
public String getHeader(String name) {
// 先从原本的Request中获取头,如果为空且名字为token,则从返回自定义的值,否则返回原有的值
String superHeader = super.getHeader(name);
if (headerName.equals(name) && (null == superHeader || "".equals(superHeader.trim()))) {
return headerValue;
}
return superHeader;
}
@Override
public Cookie[] getCookies() {
Cookie[] cookies = super.getCookies();
//纯新增
if(null == cookies){
cookies = new Cookie[1];
cookies[0] = new Cookie(cookiesName,cookiesValue);
return cookies;
}
//原有数据
for (Cookie cookie : cookies) {
if(cookiesName.equals(cookie.getName())){
cookie.setValue(cookiesValue);
return cookies;
}
}
//原有数据和新增
cookies= Arrays.copyOf(cookies,cookies.length+1);
cookies[cookies.length-1] = new Cookie(cookiesName,cookiesValue);
return cookies;
}
};
chain.doFilter(requestWrapper, response);
}
@Override
public void destroy() {
}
}
四、end
好了,打完收工。有问题请评论探讨,3q。