故事背景
需求是一个上线系统中,要嵌入一个qa的自动化测试流程,上线系统的域名和qa自动化测试的域名是独立的,为了好理解,胡编两个域名,上线系统:www.shagnxian.com, 测试接口域名:www.ceshi.com, 我们需要在上线系统的代码中调用 www.ceshi.com/gettestlist 接口。
故事经过
接口拿过来,放到浏览器地址栏,直接一敲,结果正常显示到了浏览器里,大结局。
项目是个老项目,用的reqwest请求库,项目中调用了qa同学给的接口,不出意外的挂掉了。
直接js请求调用其他域名的接口,浏览器显示跨域了,依照我多年cv的经验,加入一个跨域请求白名单,应该可以解决此问题,于是联系qa同学加了了跨域配置,为了测试方便,直接 * 了
Access-Control-Allow-Origin: *
重启服务后测试,结果仍然不行
查看请求代码后,发现代码代码设置有这么一行
reqwest({
url:'http://www.ceshi.com/gettestlist',
method:'get',
contentType: 'application/json', // 问题出在这里
})
翻阅相关资料,发现跨域设置默认只能使用简单请求: 如果Content-Type 的值仅限于以下三种简单请求:
text/plain
multipart/form-data
application/x-www-form-urlencoded
在这三者之外其他 contentType属于 预检请求,此类请求需要设置 Access-Control-Request-Headers,所以在服务器配置新增如下配置:
Access-Control-Allow-Headers: content-type, X-Requested-With
增加后接口可以正常访问。下边是当前接口response Header配置
此时的配置是大概是这样,可以应对一些增加其他配置的请求
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'content-type,Content-Length, Authorization,Origin,Accept,X-Requested-With'); //允许的请求头
res.header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, PUT'); //允许的请求方法
所以这就完了么?并没有 上线平台和测试平台都需要校验登录,目前接口通了,有一个好消息和一个坏消息:
好消息是上线平台和测试平台使用的cookie是同一个
坏消息是跨域请求过程中接口并没有把cookie带过去
所以又搜索了第三方cookie相关的内容:服务器配置需要新增
Access-Control-Allow-Credentials: true
同时请求代码也要加入相关配置,针对xhr请求:
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://example.com/', true);
xhr.withCredentials = true; // 需要新增这条配置
xhr.send(null);
针对fetch请求:
fetch(url, {
credentials: 'include'
})
所以在项目请求代码修改成以下代码:
reqwest({
url:'http://www.ceshi.com/gettestlist',
method:'get',
withCredentials: true
contentType: 'application/json', // 问题出在这里
})
再次请求,仍然不行,继续查资料,mdn相关文档有下边一句话:
备注: 当响应的是附带身份凭证的请求时,服务端 必须 明确 Access-Control-Allow-Origin 的值,而不能使用通配符“”。*
所以问题出在
res.header('Access-Control-Allow-Origin', '*');
把星号改为具体域名后,请求不再报跨域了,此时服务器跨域设置如下:
res.header('Access-Control-Allow-Origin','http://localhost:8082'); //当允许携带cookies此处的白名单不能写’*’
res.header('Access-Control-Allow-Headers','content-type,Content-Length, Authorization,Origin,Accept,X-Requested-With'); //允许的请求头
res.header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, PUT'); //允许的请求方法
res.header('Access-Control-Allow-Credentials',true); //允许携带cookies
此时接口不再提示跨域,但cookie项却依旧被拦了,
cookie的SameSite设置默认没有设置,必须在种cookie时设置 SameSite: None,浏览器才不会拦截。我们使用的cookie是统一登录平台种的cookie,目前肯定不能增加此配置,到此为止,跨域请求这条路被彻底堵死了。后边联系qa同学,最终结论是直接配置slb域名转发,没事儿了,挺好的。
参考: