信息发布→ 登录 注册 退出

如何使用RequestHeaders添加自定义参数

发布时间:2026-01-11

点击量:
目录
  • RequestHeaders添加自定义参数
    • 问题一
    • 原因
    • 解决方案
  • 修改request中header的值

    RequestHeaders添加自定义参数

    在开发过程中有的时候,参数需要绑定到requestHeaders中,而并不是在body中进行传输。这个时候就需要我们自己定义参数(需要后台的配合)

    setToken() {
        let token = localStorage.getItem('token') ? localStorage.getItem('token') : ''
        this.instance.defaults.headers.common['tokens'] = token
      }
    // 使用axios添加requestHeaders参数。封装到ajax请求中~

    问题一

    在浏览器的console中报错:自定义字段不被允许

    Request header field自定义字段 is not allowed by Access-Control-Allow-Headers

    原因

    包含自定义header字段的跨域请求,浏览器会先向服务器发送OPTIONS请求,探测该服务器是否允许自定义的跨域字段。

    如果允许,则继续实际的POST/GET正常请求,否则,返回标题所示错误。

    同时在requestHeaders请求中有你定义的字段,但结果不是我们想要的

    在responseHeaders中Access-Control-Allow-Headers中表示服务器允许跨域请求的参数

    Access-Control-Allow-Headers: Content-Type, x-requested-with, X-Custom-Header, Authorization,token

    解决方案

    服务端需要对OPTIONS请求做出应答,应答header中包含Access-Control-Allow-Headers,且值包含options请求中Access-Control-Request-Headers的值。

    以下为java服务端filter中设置的OPTIONS请求处理代码。

    @Override 
    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException { 
        try { 
            HttpServletRequest hreq = (HttpServletRequest) req;  
            HttpServletResponse hresp = (HttpServletResponse) resp;
     
            //跨域
            hresp.setHeader("Access-Control-Allow-Origin", "*"); 
     
            //跨域 Header 
            hresp.setHeader("Access-Control-Allow-Methods", "*"); 
            hresp.setHeader("Access-Control-Allow-Headers", "Content-Type,TOKENS");  // 在这里配置你要定义的参数         
     
            // 浏览器是会先发一次options请求,如果请求通过,则继续发送正式的post请求 
            // 配置options的请求返回
     
            if (hreq.getMethod().equals("OPTIONS")) { 
                hresp.setStatus(HttpStatus.SC_OK); 
                // hresp.setContentLength(0); 
                hresp.getWriter().write("OPTIONS returns OK"); 
                return; 
            }
     
            // Filter 只是链式处理,请求依然转发到目的地址。
     
            chain.doFilter(req, resp); 
        } catch (Exception e) { 
            e.printStackTrace(); 
        } 
    }

    其中,这个就是所需设置的应答Header:

    hresp.setHeader("Access-Control-Allow-Headers", "Content-Type,TOKENS");

    * header中对值的大小写貌似不敏感。

    修改request中header的值

    在java web开发中,我们有时候会遇到需要修改request中请求值的问题,虽然这个不是特别常见。初看这是一个简单的问题,因为我们能通过HttpServletRequest对象拿到我们需要的所有关于当前这个请求的所有信息,想当然的也就可以修改所以这些信息。可实际情况是HttpServletReques中很多的属性只有getter方法,而没有setter方法,也就是说我们不可以修改他们。

    记得第一次遇到这种问题还是初学编程的时候,最近又遇到这个问题,就记录一下。最近遇到的是在spring mvc中,使用@RequestBody注解把requestBody中的json映射到java的object。我们知道对于spring mvc来说,这样使用的时候需要在请求的header里面表明conten-type为application/json。如果完全是自己开发的系统,没有问题加上就是,但是当和第三方合作的时候,请求的发起方式就不是我们能控制住的了。现在的问题是如果使用spring mvc的这种开发模式,必须要在请求的header中设置content-type为application/json,但是第三方又不方便设置。所以只能在所有针对第三方的API中进行特殊处理。

    sping mvc是基于servlet的,我们只要在请求进入servlet之前在header中设置content-type为application/json就ok了,所以理想的修改方式就是加入一个filter。现在就到了关键的问题:怎么修改请求的header值。答案是利用HttpServletRequestWrapper类。 

        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                throws IOException, ServletException {
            chain.doFilter(new CustomeizedRequest((HttpServletRequest) request), response);
        } 
        private class CustomeizedRequest extends HttpServletRequestWrapper { 
            public CustomeizedRequest(HttpServletRequest request) {
                super(request);
            }
     
            @Override
            public Enumeration<String> getHeaders(String name) {
                if (null != name && name.equals("Content-Type")) {
                    return new Enumeration<String>() {
                        private boolean hasGetted = false; 
                        @Override
                        public String nextElement() {
                            if (hasGetted) {
                                throw new NoSuchElementException();
                            } else {
                                hasGetted = true;
                                return "application/json;charset=utf-8";
                            }
                        } 
                        @Override
                        public boolean hasMoreElements() {
                            return !hasGetted;
                        }
                    };
                }
                return super.getHeaders(name);
            }
        }

    demo中只重写了getHeaders方法,实际上严谨的做法是getHeader(String name)方法也要被重写。实质上我们还是没有改变header中的值的能力,但是我们重写了getHeaders方法,当发现是我们的Content-Type字段时,只要返回我们想要设置的值就OK了。同理我们可以任意发挥,根据实际的情况去重写相应的方法。

    说一下我在这里遇到的一个问题,在开发过程中使用的maven加jetty插件,运行起来没有问题。但是测试和生产环境用的是tomcat,上了测试环境发现没有效果。第一感觉是不同的容器中Content-Type的大小写或写法不一样。打了一个log继续测试,发现tomcat好像根本没进入我的getHeaders方法,就开始怀疑tomcat和jetty的某些实现不一致,各种查找没有结果。最后在本地换成tomcat来debug,竟然进入了重写的getHeaders方法,再一看name的值是:content-type。粗心把log打错位置了。。。,刚开始猜想的是对的。

    所以这里的name.equals("Content-Type")就要考虑大小写和不同写法的因素了(比如contenttype或ContentType)。

    后来想了一下之所以会出现这个失误有两个原因:

    • 粗心 log打错位置
    • 自身对于容器不熟悉,而且之前遇到过tomcat和jetty对于某些请求作不同处理的情况,所以就找错了方向。

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持。

    在线客服
    服务热线

    服务热线

    4008888355

    微信咨询
    二维码
    返回顶部
    ×二维码

    截屏,微信识别二维码

    打开微信

    微信号已复制,请打开微信添加咨询详情!