前后端分离项目的跨域及保持Session会话
当Web项目前后端分离开发的时候, 由于域名不一致, 会出现无法请求和无法维持会话的情况
OPTIONS
在前端Ajax请求后台的时候, 打开控制台可以看到, 每一次请求之前都会有一次OPTIONS
类型的请求OPTIONS
称为预检请求, 通过这个请求, 浏览器会告知服务器,接下来的请求的情况
1 | Access-Control-Request-Method: POST |
得到服务器的回应后浏览器便知道这次请求是否被允许
OPTIONS的处理
后台可以在拦截器或过滤器中处理这个请求, 这里以Springboot后台的拦截器为例
1 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) { |
Access-Control-Allow-Origin
代表允许请求源, 设置为*
或设置为前端的域名即可解决跨域无法请求的问题例如http://domain
Access-Control-Allow-Methods
表示允许的请求方式
以下两个特别说明Access-Control-Allow-Headers
代表允许浏览器
可以向 服务器
发送哪些请求头Access-Control-Expose-Headers
代表允许浏览器
可以读取哪些服务器
发送的请求头
均限制在客户端上
利用Token保持会话
传统开发前后端能维持会话, 是因为当服务器调用了HttpSession
时, 会将SessionId
放在请求头的set-cookie
中, 浏览器读取到了这个信息, 就把SessionId
保存在本地, 待下次请求时以Cookie
的形式带给服务器, 服务器根据收到的SessionId
找到Session
以继续会话
现在由于前后端分离后使用Cookie
的种种不便, 可以换另一种方式来进行SessionId
的传输, 就是把SessionId
放在请求头中带给浏览器
接上一段代码
1 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) { |
由于设置了response.setHeader("Access-Control-Expose-Headers", "TK");
表示客户端可以读取header中的TK
字段, 客户端就可以读取放在TK
中的SessionId
保存到本地, 存储方式可以是Cookie
或者是LocalStorage
都可以
当需要请求时用http://service;jsessionid=${token}
的形式传给服务器, 这个与传统Web中Cookie:JSESSIONID=sessionid
的形式效果是一致的
如此就达到了保持会话的目的了
为什么能维持会话
服务器根据sessionid
保持会话这件事是容器完成的, 根据的就是请求中所传来的URL后的;jsessionid=
或者 cookie中的JSESSIONID=
,
容器根据sessionid
自动找到内存中的Session。
这也是选择;jsessionid=
方式的原因。这会让你没有感觉像在做前后端分离的开发, 就像传统的JSP开发一样, 前后端融合在一起。
当然你也可以用其他方式手动操作, 比如直接传参 http://service?JID=${token}
, 在请求头中带过去之类的, 然后手动取得ID再去找对应的Session, 不过这就有点多此一举了