HttpServletRequest增加header
由于在请求中请求域的属性在请求转发,路由等过程中,请求域的值会丢失,在项目项目中使用请求头来传递信息,但是HttpRequest并没有实现增加请求头的方法,所以找到他的子类来实现
- class MutableHttpServletRequest extends HttpServletRequestWrapper {
- // holds custom header and value mapping
- private final Map<String, String> customHeaders;
- public MutableHttpServletRequest(HttpServletRequest request){
- super(request);
- this.customHeaders = new HashMap<String, String>();
- }
- public void putHeader(String name, String value){
- this.customHeaders.put(name, value);
- }
- public String getHeader(String name) {
- // check the custom headers first
- String headerValue = customHeaders.get(name);
- if (headerValue != null){
- return headerValue;
- }
- // else return from into the original wrapped object
- return ((HttpServletRequest) getRequest()).getHeader(name);
- }
- public Enumeration<String> getHeaderNames() {
- // create a set of the custom header names
- Set<String> set = new HashSet<String>(customHeaders.keySet());
- // now add the headers from the wrapped request object
- @SuppressWarnings("unchecked")
- Enumeration<String> e = ((HttpServletRequest) getRequest()).getHeaderNames();
- while (e.hasMoreElements()) {
- // add the names of the request headers into the list
- String n = e.nextElement();
- set.add(n);
- }
- // create an enumeration from the set and return
- return Collections.enumeration(set);
- }
- }
使用:
- public class SecurityFilter implements javax.servlet.Filter {
- @Override
- public void destroy() {
- }
- @Override
- public void doFilter(ServletRequest request, ServletResponse response,
- FilterChain chain) throws IOException, ServletException {
- HttpServletRequest req = (HttpServletRequest) request;
- MutableHttpServletRequest mutableRequest = new MutableHttpServletRequest(req);
- ...
- mutableRequest.putHeader("x-custom-header", "custom value");
- chain.doFilter(mutableRequest, response);
- }
- @Override
- public void init(FilterConfig filterConfig) throws ServletException {
- }
- }
但是项目中我使用的SpringCloud ZUUL中使用这样 的方式失败:
- @Component
- public class AccessFilter extends ZuulFilter {
- private Logger log = LoggerFactory.getLogger(AccessFilter.class);
- @Autowired
- private VerificationHelper helper;
- private BufferedReader reader=null;
- @Autowired
- private KeyAndFrequencyService service;
- @Autowired
- private ZuulTest zuulTest;
- @Autowired
- private PermissionHandler permissionHandler;
- @Override
- public String filterType() {
- //前置过滤器
- return "pre";
- }
- @Override
- public int filterOrder() {
- //优先级,数字越大,优先级越低
- return 0;
- }
- @Override
- public boolean shouldFilter() {
- //是否执行该过滤器,true代表需要过滤
- return true;
- }
- @Override
- public Object run() {
- RequestContext ctx = RequestContext.getCurrentContext();
- HttpServletRequest request = ctx.getRequest();
- try {
- permissionHandler.setTokenExpireTime(200000000);
- String type = request.getHeader("type");
- zuulTest.say();
- System.out.println("......................................................");
- if (type == null) {
- System.out.println("......................................................验证1");
- Object object = helper.AccessZuul(request, ctx);
- return object;
- } else {
- System.out.println("......................................................验证2");
- PermissionResult result=permissionHandler.check(request);
- System.out.println(result);
- if(result.isState()){
- MutableHttpServletRequest mutRequest=new MutableHttpServletRequest (request);
- //增加头部信息
- DasAccountInfo accountInfo= permissionHandler.GetDasAccountInfoById(Integer.parseInt(result.getUserId()));
- mutRequest.putHeader("dasAccountInfo", JSON.toJSONString(disablePropertyName())) ;RequestContext.getCurrentContext().setRequest(mutRequest);
- ctx.setSendZuulResponse(true);// 对该请求进行路由
- ctx.setResponseStatusCode(200);
- ctx.set("isSuccess", true);
- }else{
- ctx.setSendZuulResponse(false);// 过滤该请求,不对其进行路由
- ctx.setResponseStatusCode(401);// 返回错误码
- ctx.setResponseBody("{\"code\":0,\"result\":\"网关验证失败!验证方式为2\"}");// 返回错误内容
- ctx.set("isSuccess", false);
- }
- }
- }catch (Exception e){
- e.printStackTrace();
- log.error("网关报错!!!",e.fillInStackTrace());
- }
- return null;
- }
使用zuul网关的自带的设置请求头的方法,在网关中设置的请求头可以被路由下面的服务获取到:
- ctx.getZuulRequestHeaders().put("dasAccountInfo", JSON.toJSONString(disablePropertyName()));
修改HttpServletRequest中header的信息
废话一堆:由于业务有统一的鉴权系统,页面请求时在header中带过来gsid,正常业务没有问题,但是当需要下载文件时,前端统一用json解析响应,当响应文件时,对于前端来说不好处理,就决定使用简单的get请求下载文件,将gsid通过url带过来,这样的话后端鉴权就需要处理,当header中没有gsid时,从参数中取,为了尽可能少的改变公用的业务代码(指sso),就在当前项目中自定义权限拦截器。
总结一句,我就是想想header中加东西!!往下看具体实现方式:
新建拦截器类,继承原有的拦截器,重写其preHandle方法
- @Override
- public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {
- String gsid = request.getHeader("GSID");
- if(StringUtils.isBlank(gsid)){
- String gsid= request.getParameter("GSID");
- //使用反射,将gsid设置到request中的的header中去
- reflectSetparam(request,"GSID",gsid);
- log.info("请求连接中的gsid={}",request.getHeader("GSID"));
- }
- return super.preHandle(request, response, o);
- }
说明:可以看到在方法中,
1、先进行header信息判断,如果header中没有GSID,就去请求参数中拿
- gsid= request.getParameter("GSID");
2、通过反射将参数中的GSID键值对儿:“GSID”:“376645354562335”加入到header中去
话不多少,先上代码,再解释:
解释:
- /**
- * 修改header信息,key-value键值对儿加入到header中
- * @param request
- * @param key
- * @param value
- */
- private void reflectSetparam(HttpServletRequest request,String key,String value){
- Class<? extends HttpServletRequest> requestClass = request.getClass();
- System.out.println("request实现类="+requestClass.getName());
- 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);
- System.out.println("coyoteRequest实现类="+o1.getClass().getName());
- Field headers = o1.getClass().getDeclaredField("headers");
- headers.setAccessible(true);
- MimeHeaders o2 = (MimeHeaders)headers.get(o1);
- o2.addValue(key).setString(value);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
执行打印信息如下:
request实现类=org.apache.catalina.connector.RequestFacade
coyoteRequest实现类=org.apache.coyote.Request
看HttpServletRequest的源码,是个接口,并且我们获取header信息的方法是getHeader()方法,按常理其对象中应该有header字段,那么我们就去实现类中找这个字段,具体过程如下
步骤一:先找到具体的Request对象是哪个类,根据打印信息看源码
进入其中找到getHeader()方法,如下
- public String getHeader(String name) {
- if (this.request == null) {
- throw new IllegalStateException(sm.getString("requestFacade.nullRequest"));
- } else {
- return this.request.getHeader(name);
- }
- }
然后我们找this.request
这个request,我们找到它的类型,点击去
这个类的全路径是:org.apache.catalina.connector.Request
这个类中找getHeader方法
- public String getHeader(String name) {
- return this.coyoteRequest.getHeader(name);
- }
找到这个类中的coyoteRequest
- protected org.apache.coyote.Request coyoteRequest;
是这样的
再找到getHeader()
- public String getHeader(String name) {
- return this.headers.getHeader(name);
- }
好了,终于见到属性了
- private final MimeHeaders headers = new MimeHeaders();
找到MineHeaders中的getHeader方法,
- public String getHeader(String name) {
- MessageBytes mh = this.getValue(name);
- return mh != null ? mh.toString() : null;
- }
看到最终header是一个MessageBytes对象,好找到这个对象进去,发现只能setValue,那就在MineHeaders中找在哪里实例化MessageBytes对象的
找了半天找到在createHeader()方法中实例化MimeHeaderField对象,然后这个对象实例化时会实例化MessageBytes对象
这里有name,value,靠谱
然后再在MimeHeader中找在addValue方法中有调用,就用这个试一下吧,然后就是最上面的我自定义的方法,在heade中加入了一个键值对儿。
测试请求:
http://127.0.0.1:32100/v1/CustomerRefundRest/exportRefund?gsid=abc114f1bd0d484084e5df3fe1c419b8&refundLongStartDate=1520611199000&refundLongEndDate=1522943999000
测试打印结果:
OVER!以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。
原文链接:https://blog.csdn.net/didi7696/article/details/83508499