背景
这边要开发一套带有权限认证的平台,懒得自己写拦截器,于是还是打算利用Shiro安全框架,由于采用的还是Cookie-Session那老一套,并没有封装成token暂时也不用考虑集群多实例共享session的问题,所以其实前端的每次请求报文都是需要携带cookie的,cookie里面的jsessionid就是验证对应服务端中的session-data能否匹配。但是这次联调处理并不顺利,还是在开发阶段就问题频出。
在CORS协议中,前端如果需要每次携带cookie,就得把withCredentials设置成true。所以在开发阶段我将配置类的Access-Control-Allow-Origin设置成*,Access-Control-Allow-Credentials设置成true。
但是在遇到PUT方法的接口(非预检请求)时,由于options类型的预检请求不带cookie所以被拦截在外。
非简单请求
请求分为非简单请求和简单请求,其中预检请求就是导致我们联调发生的问题的原因。
非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json。
非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为”预检”请求(preflight)。
浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。
这里引用阮一峰的网络日志的一篇名为《跨域资源共享CORS详解》解释。当请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json就会触发询问服务器的回应,要求服务器确认可以这样请求。
之前的配置类由于服务端未放行,导致触发错误。
解决方法
我们将需要预检请求的方法"OPTIONS".equals(request.getMethod())放行,同时把Access-Control-Allow-Headers和Access-Control-Allow-Origin设置成请求的HTTP头信息,这样可以保证都放行。实际的配置就是如下:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 
 | 
 
 
 
 
 
 @WebFilter(filterName = "CorsFilterConfig ")
 @Order(-100)
 @Component
 @ServletComponentScan
 public class CorsFilterConfig implements Filter {
 
 private static final Logger logger = LoggerFactory.getLogger(CorsFilterConfig.class);
 
 private static String[] allowDomains = {"http://localhost:8080", "http://localhost:80", "http://ip:8080", "http://ip:80"};
 
 
 @Override
 public void init(FilterConfig filterConfig) throws ServletException {
 }
 
 @Override
 public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
 
 HttpServletRequest request = (HttpServletRequest) req;
 HttpServletResponse response = (HttpServletResponse) res;
 response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
 response.setHeader("Access-Control-Allow-Credentials", "true");
 response.setHeader("Access-Control-Allow-Methods", "POST,GET,PATCH,DELETE,PUT,OPTIONS");
 
 
 
 
 response.setHeader("Access-Control-Max-Age", "3600");
 response.setHeader("Access-Control-Allow-Headers", request.getHeader("Access-Control-Request-Headers"));
 response.setHeader("Content-Type","application/json;charset=UTF-8");
 
 if ("OPTIONS".equals(request.getMethod())) {
 response.setStatus( 200 );
 return;
 }
 chain.doFilter(req, res);
 }
 
 @Override
 public void destroy() {
 
 }
 
 }
 
 
 |