springboot cors跨域问题,为什么用interceptor拦截部到OPTIONS请求?
关于什么是cors就不多说了,有很多不错的文章
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/AccesscontrolCORS
https://www.cnblogs.com/yuansc/p/9076604.html
笔者并没有完全用网上提供的方法来处理。没有用springboot默认支持的cors的处理办法。 而是选择用spring的拦截器来拦截OPTIONS请求。
在拦截器的preHandle方法中对OPTIONS请求做了拦截处理,判断如果是OPTIONS请求就会设置响应的响应头
经过测试拦截器拦截不到OPTIONS请求,换句话说就是OPTIONS请求还没走到拦截器就返回了。
这里就需要了解一下一个请求到拦截器经历了哪些步骤,OPTIONS请求是在那一步就返回了。
大概的步骤如下
request ---> filter(过滤器)----> dispatcherservelet的doservice方法 ----> interceptoor拦截器
既然请求没走到拦截器,我没有没有写过滤器,所以肯定是在doservice方法或者在filter到doservice方法之间就被返回了。
带着问题来看源码,我们来找到服务器容器是在那里处理OPTIONS请求的
于是找到了FrameworkServlet类中有一个doOptions方法,实际上这个方法的调用是在dispatcherservlet的doservice方法之前的,调用processRequest(request, response);方法才会走到doservice方法。
这个方法里判断了 this.dispatchOptionsRequest || CorsUtils.isPreFlightRequest(request)
this.dispatchOptionsRequest默认是false的,所以来看CorsUtils.isPreFlightRequest(request)
这个方法又会调用三个判断条件 其中:
- isCorsRequest方法如下:就判断了request的消息头中是否包含orgin这个消息头
- HttpMethod.OPTIONS.matches(request.getMethod())判断这个请求是否是OPTIONS请求
- request.getHeader(HttpHeaders.ACCESSCONTROLREQUEST_METHOD) != null就更直观,直接判断消息头是否有Access-Control-Request-Method这个消息头
所以现在问题就是是否这三个条件都满足,CorsUtils.isPreFlightRequest(request)返回结果为true,才会走到doservice方法。
经排查,是因为前端没有设置orgin和Access-Control-Request-Method这两个消息头 设置上这两个消息头就可以顺利走到拦截器,并且成功设置cors消息头
问题到这里就解决的,但是其实如果一开始就在过滤器filter中来处理,就不会有这个问题了。doOptions方法是在拦截器之后的。无论设不设消息头都可以成功设置消息头