ajax跨域sessionfilter
Posted 1501220038
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ajax跨域sessionfilter相关的知识,希望对你有一定的参考价值。
在web开发中,标题列举的这几项内容都是很常见的,遇到问题也不难解决。但最近我在项目中却遇到一个这几项组合出的问题,卡了好几个小时,值得记一下。
首先项目是前后端分离的结构。前端我用nodejs来调试,后端用spring boot跑的各种接口。因为两者端口不同,所以首先得解决跨域调用问题。通常有简便的方法我就不会去用麻烦的方法,所以直接在接口上加注解@CrossOrigin,轻松搞定。
接着发现虽然大部分功能接口调用正常,但是获取profile信息的接口不行。profile信息是从session中获取的。那么自然想到跨域的session没有解决。随便一搜答案很多,在jquery调用时加上一个属性xhrFields: withCredentials: true 即可。此时前端有个报错The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*',原因是因为加了这个属性后@CrossOrigin就不能再用默认值(默认值是*,表示任意地址都可以跨域访问)。这个好办,加上域名限制@CrossOrigin(value="http://localhost:8000")。这里还有个注意点,开始我没写http://,光写域名是不行的。然而还是报错The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true'。原来Access-Control-Allow-Credentials也不能是默认值'',必须为true。也不说一次说清楚,大喘气啊,接着加@CrossOrigin(value="http://localhost:8000",allowCredentials="true")。好了,登录、获取profile信息都正常,十多分钟全解决了,乐呵呵继续。
然而naive了,在获取一个需要权限验证的接口时,怎么都获取不到。因为权限验证是通过一个filter来获取session中的用户信息判断的。那么按理来说和之前的get profile是一样的。前端写法也是一模一样的,为什么一个能获取到一个不行呢。于是各种自我怀疑、花样尝试。好几个小时过去了,就在打算放弃、曲线救国的时候,猛然发现发送这个请求的方法是options,可是我分明用的是post方法。查阅了一下相关资料,options是一个“探测”请求。当发送的是简单请求时,ajax就直接发出去了。(简单请求指的是以下HTTP方法之一:HEAD、GET、POST且Content-Type的值为text/plain、multipart/form-data或application/x-www-form-urlencoded);如果不是简单请求,ajax会先发一个options方法的预检请求以确认对方是否可以接收。我这个接口恰恰是提交json格式的查询条件,所以先发了一个options请求。而且貌似发送options请求时默认就不会带上cookie,于是第一轮请求就被过滤器拦截返回401了,真正的请求就没发出去。猜到是这个原因之后,改写了一下filter:
String method = req.getMethod();
if(method.equals("OPTIONS"))
chain.doFilter(request, response);
else... ...
如果是options方法直接放过,真正的判断逻辑放在else里。终于顺利通过了。
虽然是一个不太常见的组合情景,但也说明自己对http协议的了解还是不够深入,真是学无止境啊。
继续又发现一个问题,当被过滤器拦截返回401代码时,ajax 的error.status却是404,导致转向的错误提示页不正常。后来发现是这样的,因为在过滤器处理时忘了加消息头,所以尽管返回状态码是401,但浏览器仍然认为是无法访问(404)。把filter里加上信息头就可以了。
关键是这个:res.setHeader("Access-Control-Allow-Origin", req.getHeader("Origin"));
以上是关于ajax跨域sessionfilter的主要内容,如果未能解决你的问题,请参考以下文章
play for scala 实现SessionFilter 过滤未登录用户跳转到登录页面