如何给HttpServletRequest增加消息头


Posted in Java/Android onJune 30, 2021

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

如何给HttpServletRequest增加消息头

这个request,我们找到它的类型,点击去

如何给HttpServletRequest增加消息头

这个类的全路径是:org.apache.catalina.connector.Request

这个类中找getHeader方法

public String getHeader(String name) {
    return this.coyoteRequest.getHeader(name);
}

找到这个类中的coyoteRequest

protected org.apache.coyote.Request coyoteRequest;

是这样的

如何给HttpServletRequest增加消息头

再找到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对象

如何给HttpServletRequest增加消息头

这里有name,value,靠谱

然后再在MimeHeader中找在addValue方法中有调用,就用这个试一下吧,然后就是最上面的我自定义的方法,在heade中加入了一个键值对儿。

测试请求:

http://127.0.0.1:32100/v1/CustomerRefundRest/exportRefund?gsid=abc114f1bd0d484084e5df3fe1c419b8&refundLongStartDate=1520611199000&refundLongEndDate=1522943999000

测试打印结果:

如何给HttpServletRequest增加消息头如何给HttpServletRequest增加消息头

OVER!以上为个人经验,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Java/Android 相关文章推荐
SpringBoot集成Redis,并自定义对象序列化操作
Jun 22 Java/Android
Java中使用Filter过滤器的方法
Jun 28 Java/Android
Java 语言中Object 类和System 类详解
Jul 07 Java/Android
使用@Value值注入及配置文件组件扫描
Jul 09 Java/Android
java设计模式--七大原则详解
Jul 21 Java/Android
idea 在springboot中使用lombok插件的方法
Aug 02 Java/Android
springboot 多数据源配置不生效遇到的坑及解决
Nov 17 Java/Android
聊聊SpringBoot自动装配的魔力
Nov 17 Java/Android
Java 在线考试云平台的实现
Nov 23 Java/Android
Java异常处理try catch的基本用法
Dec 06 Java/Android
Spring Cloud Netflix 套件中的负载均衡组件 Ribbon
Apr 13 Java/Android
Spring Boot优化后启动速度快到飞起技巧示例
Jul 23 Java/Android
解决ObjectMapper.convertValue() 遇到的一些问题
Jun 30 #Java/Android
Java基础之详解HashSet的使用方法
Java实现多文件上传功能
Jun 30 #Java/Android
Java基础之线程锁相关知识总结
Jun 30 #Java/Android
详解Spring事件发布与监听机制
浅谈自定义校验注解ConstraintValidator
ObjectMapper 如何忽略字段大小写
You might like
用PHP调用Oracle存储过程的方法
2008/09/12 PHP
PHP 一个页面执行时间类代码
2010/03/05 PHP
php中根据某年第几天计算出日期年月日的代码
2011/02/24 PHP
PHP实现的简单AES加密解密算法实例
2017/05/29 PHP
PHP结合Ffmpeg快速搭建流媒体服务的实践记录
2018/10/31 PHP
dojo 之基础篇
2007/03/24 Javascript
jquery radio 操作代码
2011/03/16 Javascript
Select标签下拉列表二级联动级联实例代码
2014/02/07 Javascript
实例讲解JQuery中this和$(this)区别
2014/12/08 Javascript
JavaScript数组对象实现增加一个返回随机元素的方法
2015/07/27 Javascript
jquery实现通用的内容渐显Tab选项卡效果
2015/09/07 Javascript
JS实现将Asp.Net的DateTime Json类型转换为标准时间的方法
2016/08/02 Javascript
jQuery给指定的table动态添加删除行的操作方法
2016/10/12 Javascript
WEB 前端开发中防治重复提交的实现方法
2016/10/26 Javascript
js实现登录框鼠标拖拽效果
2017/03/09 Javascript
javascript数据结构中栈的应用之符号平衡问题
2017/04/11 Javascript
vue拦截器Vue.http.interceptors.push使用详解
2017/04/22 Javascript
详谈for循环里面的break和continue语句
2017/07/20 Javascript
详解前端路由实现与react-router使用姿势
2017/08/07 Javascript
EasyUI框架 使用Ajax提交注册信息的实现代码
2017/09/27 Javascript
AngularJS中控制器函数的定义与使用方法示例
2017/10/10 Javascript
vue中实现在外部调用methods的方法(推荐)
2018/02/08 Javascript
JavaScript代码异常监控实现过程详解
2020/02/17 Javascript
vue样式穿透 ::v-deep的具体使用
2020/06/04 Javascript
jquery+ajax实现异步上传文件显示进度条
2020/08/17 jQuery
Python 网页解析HTMLParse的实例详解
2017/08/10 Python
Python 3.6 读取并操作文件内容的实例
2018/04/23 Python
scrapy-redis的安装部署步骤讲解
2019/02/27 Python
党员思想汇报范文
2013/12/30 职场文书
党章学习思想汇报
2014/01/14 职场文书
商场端午节活动方案
2014/01/29 职场文书
党的群众路线教育实践活动领导班子对照检查材料
2014/09/25 职场文书
党支部班子“四风”问题自我剖析材料
2014/09/28 职场文书
Python使用openpyxl批量处理数据
2021/06/23 Python
基于Python实现股票收益率分析
2022/04/02 Python
GO语言异常处理分析 err接口及defer延迟
2022/04/14 Golang