之前有写过什么样情况下是跨域和一般跨域的解决方案。
之前状态
我在工作中 一般遇到跨域会通过jsonp或者同域代理来解决。一般情况下不需要使用其他的技术方案。
需求场景
前端:
各个独立域名的系统需要统一公共头及导航。对接统一的用户中心及导航权限。
后端:
使用node像前端下发,需要当前用户权限。
开发
我开始按照正常开发接口来进行开发,调试,ok接口没问题。
交给同组负责前端同事。
他一调,接口报错。看一眼日志 后台报错没有session,主域下的cookie并没有发送过来。
由于浏览器的安全策略,跨域不允许携带cookie,jsonp也不允许携带cookie。
那就需要前端ajax设置
1 | withCredentials = true |
服务端设置
1 | Access-Control-Allow-Credentials: true |
因为我们多个系统,需要多个域名,所以我做了一个操作
1 | let url = req.headers.origin || req.headers.host; |
哪个个域名来调用 Access-Control-Allow-Origin 就返回它当前的域名,并且做了相对应的安全性校验,必须是我们的系统的域名才允许通过。
POST
经过上面的操作get请求成功拿到cookie,并且获取到对应的session。
接下来POST请求出现了另一个问题,请求又被浏览器block。google一番发现问题所在
具体的原因嘛,是因为预请求没有通过控制访问检查,更具体的原因是预请求不允许重定向。
1 | 关键词 preflight request |
为什么要发预检请求
preflight request是为确保服务器是否允许发起对服务器数据产生副作用的HTTP请求方法,
而预先由浏览器发起OPTIONS方法的一个预检请求,
如果允许就发送真实的请求,如果不允许则直接拒绝发起真实请求。
首先介绍不会触发预检请求的方法
- GET
- HEAD
- POST
仅当POST方法的Content-Type值等于下列之一才算做简单需求
- text/plain
- multipart/form-data
- application/x-www-form-urlencoded
因为我们这里使用了axios,而axios的post方法Content-Type默认是application/json; charset=utf-8;所以如何避免post触发预检请求的关键就是使用上述Content-Type的三个任一值,application/x-www-form-urlencoded才是最大淫家。
接口层面也对应接收 application/x-www-form-urlencoded 。
问题解决。