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

目录
  • 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对于某些请求作不同处理的情况,所以就找错了方向。

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

(0)

相关推荐

  • 如何给HttpServletRequest增加消息头

    HttpServletRequest增加header 由于在请求中请求域的属性在请求转发,路由等过程中,请求域的值会丢失,在项目项目中使用请求头来传递信息,但是HttpRequest并没有实现增加请求头的方法,所以找到他的子类来实现 class MutableHttpServletRequest extends HttpServletRequestWrapper { // holds custom header and value mapping private final Map<String

  • java 获取HttpRequest Header的几种方法(必看篇)

    在开发应用程序的过程中,如果有多个应用,通常会通过一个portal 门户来集成,这个portal  是所有应用程序的入口,用户一旦在portal 登录之后,进入另外一个系统,就需要类似的单点登录(SSO). 进入各个子系统的时候,就不需要再次登录, 当然类似的功能,你可以通过专业的单点登录软件来实现,也可以自己写数据库token 等方式来实现.其实还有一个比较简单的方法,就是通过 portal 封装已经登录过的用户的消息,写到http header 之中,然后把请求forward 到各个子系统中

  • 使用feign服务调用添加Header参数

    feign添加Header参数 @Configuration public class FeignConfiguration implements RequestInterceptor { private static final Logger logger = LoggerFactory.getLogger(FeignConfiguration.class); @Override public void apply(RequestTemplate template) { ServletRequ

  • java swagger ui 添加header请求头参数的方法

    我用到的swagger 主要有三款产品,swagger editor,swagger ui 和swagger codegen. swagger editor:主要是一个本地客户端,用来自己添加api,自己来测试,相当于一个api的可视化测试工具和定义工具吧. swagger ui:主要用户嵌入到项目中,将所有的接口生成一个可视化的页面,方便前后端联调 swagger codegen:主要用于通过swagger来自动生成代码 我用的swagger ui主要在java项目中.将所有的http接口提供

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

    目录 RequestHeaders添加自定义参数 问题一 原因 解决方案 修改request中header的值 RequestHeaders添加自定义参数 在开发过程中有的时候,参数需要绑定到requestHeaders中,而并不是在body中进行传输.这个时候就需要我们自己定义参数(需要后台的配合) setToken() { let token = localStorage.getItem('token') ? localStorage.getItem('token') : '' this.i

  • log4j2的异步使用及添加自定义参数方式

    目录 log4j2异步使用及添加自定义参数 添加依赖(这里省略了版本号) 下面写一个生产可用的log4j2.xml的模板 补充知识 自定义日志格式 如何在日志中添加自己想传的参数? log4j 输入自定义参数 测试代码如下 log4j2异步使用及添加自定义参数 关于log4j2的性能和原理就不赘述了,这篇主要讲使用,配置文件解读,和添加自定义参数,偏应用的一篇文章. 相比与其他的日志系统,log4j2丢数据这种情况少:disruptor技术,在多线程环境下,性能高于logback等10倍以上:利

  • vue 项目@change多个参数传值多个事件的操作

    首先是只有一个change事件 changelevel()//选择值 若想改变select同时改变row里的值 多个事件用:分割开来 此时发现changelevel()不执行那么加上()呢 changelevel(val){ console.log(val) => //undefined} 表示未传参数 输出undefined 那么要传值传谁呢 传入$event 再次输出就可获取选择值 补充:element-ui @change添加自定义参数 element-ui的change事件默认参数是一个

  • 使用自定义参数解析器同一个参数支持多种Content-Type

    目录 一堆废话 探究Springmvc参数解析器工作流程 不想看废话的可以直接进结果 补充 一堆废话 事出有因, 原先上线的接口现在被要求用Java重写,按照原暴露出去的文档然后毫无疑问的,按照Java的惯例, 一定是@RequestBody然后去接收application/json;charset=utf-8,然后一通参数接收处理逻辑. 结果测试都通过了,上线的时候,刚把原接口切到新接口上,日志就狂飙 application/x-www-form-urlencoded:charset=utf-

  • ionic选择多张图片上传的示例代码

    在上一篇博客ionic本地相册.拍照.裁剪.上传(单图完全版)中,跟大家分享了ionic项目选择本地图片.拍照.裁剪.上传到服务器的内容,但是上一节的内容由于使用了Cordova的Camera插件进行了图片选择与拍摄,所以每次只能支持1张图片的选择与上传.上一篇博客中的内容适合用于头像情景. 在本节中,跟大家分享使用Corodva的ImagePicker插件,实现多图选择与上传.废话不多说,进入主题. 插件安装 cordova plugin add corodva-plugin-imagepic

  • Select2.js下拉框使用小结

    用了这么久的Select2插件,也该写篇文章总结总结.当初感觉Select2不是特别好用,但又找不到比它更好的下拉框插件. 在我的印象里Select2有2个版本,最新版本有一些新的特性,并且更新了一下方法参数,比最初版本要好看一些,本文针对新版本. 官网:http://select2.github.io/ 演示: 由于博客系统的原因,所以只能演示简单的功能. 一.文件需要引入select2.full.js.select2.min.css(4.0.1版本)和jquery.1.8.3及以上 最新版本

  • Android 全局异常捕获实例详解

    Android 全局异常捕获 今天就来说说作为程序猿的我们每天都会遇到的东西bug,出bug不可怕可怕的是没有出bug时的堆栈信息,那么对于bug的信息收集就显得尤为重要了,一般用第三方bugly或者友盟等等都能轻易收集,但是由于公司不让使用第三方,而安卓正好有原生的异常收集类UncaughtExceptionHandler,那么今天博客就从这个类开始. UncaughtExceptionHandler见名知意,即他是处理我们未捕获的异常,具体使用分两步 1.实现我们自己的异常处理类 publi

  • spring security4 添加验证码的示例代码

    spring security是一个很大的模块,本文中只涉及到了自定义参数的认证.spring security默认的验证参数只有username和password,一般来说都是不够用的.由于时间过太久,有些忘,可能有少许遗漏.好了,不废话. spring以及spring security配置采用javaConfig,版本依次为4.2.5,4.0.4 总体思路:自定义EntryPoint,添加自定义参数扩展AuthenticationToken以及AuthenticationProvider进行

  • Bootstrap table 服务器端分页功能实现方法示例

    本文实例讲述了Bootstrap table 服务器端分页功能实现方法.分享给大家供大家参考,具体如下: bootstrap版本 为 3.X bootstrap-table.min.css bootstrap-table-zh-CN.min.js bootstrap-table.min.js 前端bootstrap+jQuery,服务端使用spring MVC实现restful风格服务 前端代码块 <table id="test-table" class="col-xs

  • vue在响应头response中获取自定义headers操作

    日常开发,我们可能会为了安全问题,保证第三方无法通过伪造返回报文欺骗前端,需要在返回报文中添加自定义参数,用于验证身份,后端添加自定义参数,前端校验自定义参数通过后才会执行相应的操作. 系统为了安全会去掉自定义头,如果不做任何处理,前端无法通过javascript访问自定义头,所以需要在接口返回中添加这样的操作. response['Cookie'] ='13231231231' #自定义头 添加后接口返回信息如以下截图: 控制台打印headers信息如以下截图: 要正确打印需要在接口返回中设置

随机推荐