think
think copied to clipboard
Ajax跨域时,如何带上目标地址需要的cookie?
我们使用ajax请求时,由于浏览器的同源策略的影响偶尔会遇到跨域的情况。通常我们有以下几种跨域的解决方案:
- 设置document.domain
- 通过有src属性的标签实现跨域(如:script, img, iframe等)
- jsonp(其实也是利用了script标签的src属性)
- navigator对象(ie6/7的iframe之间,navigator对象共享)
- 跨域资源共享(CORS)
- window.postMessage
- WebSocket
- window.name
详细跨域方式参考: Web开发中跨域的几种解决方案 前端跨域问题及解决方案 如何解决 Ajax 跨域请求不到的问题?
跨域方式有那么多种,但如果遇到以下场景,该怎么解决呢?
我在a站点,想要跨域访问b站点的某一个接口,而b站点的这个接口要成功获取数据需要在a站点发起请求的时候带上一些Cookie信息
在node端,我们是可以通过修改request的headers的Cookie信息来实现(代理转发),但在浏览器端,跨域请求是不会携带Cookie的,但鉴于 Cookie 在身份验证等方面的重要性, 2014年W3C发布的CORS推荐使用额外的响应头字段来允许跨域发送 Cookie。
先来看看具体实现:
客户端
原生ajax
在open XMLHttpRequest后,设置withCredentials为true即可让该跨域请求携带 Cookie。 注意携带的是目标页面所在域的 Cookie。
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.withCredentials = true;
xhr.send();
jQuery实现
可以通过设置xhrFields属性来实现:
$.ajax({
url: url,
xhrFields: {
withCredentials: true
}
});
zepto实现
目前如果要用 zepto 来进行 CORS 的话,还是需要自己更改 zepto 的 ajax 模块代码,然后手动构建。
zepto.js v1.1.3相关源码:
if (settings.xhrFields) for (name in settings.xhrFields) xhr[name] = settings.xhrFields[name]
var async = 'async' in settings ? settings.async : true
xhr.open(settings.type, settings.url, async, settings.username, settings.password)
zepto 是在 open() 方法之前设置 XMLHttpRequest 的属性值的,所以这会导致在使用 CORS 并且设置 withCredentials 的时候,代码在部分浏览器中报错。Android webview 中重现的几率很大。
fetch实现
fetch请求默认是不带上cookie的,所以更别提跨域的时候带上cookie信息了,需要带上cookie信息需要设置fetch的credendials的值为'include'(参考),即:
fetch(url, {
credentials:"include"
}).then(success, failure)
axios实现
axios的withCredentials默认是false的,可以在发起请求的时候设置:
axios(url, {
method: "post",
data: someJsonData,
withCredentials: true
})
也可以全局设置:
axios.defaults.withCredentials = true;
服务端
以上都只是客户端来设置的,因为credentials都是基于cros的,所以还得需要服务器端配合才成。目标服务器不接受你跨域发送的Cookie,费多大的劲都是白搭,还是会被浏览器同源策略给阻拦。
服务器同时设置Access-Control-Allow-Credentials响应头为"true", 即可允许跨域请求携带 Cookie。
除了Access-Control-Allow-Credentials之外,跨域发送 Cookie 还要求 Access-Control-Allow-Origin不允许使用通配符,而且只能指定单一域名:
If the credentials flag is true and the response includes zero or more than one Access-Control-Allow-Credentials header values return fail and terminate this algorithm. ——W3C Cross-Origin Resource Sharing
否则,浏览器还是会挡住跨域请求:
既然Access-Control-Allow-Origin只允许单一域名, 服务器可能需要维护一个接受 Cookie 的 Origin 列表, 验证 Origin 请求头字段后直接将其设置为Access-Control-Allow-Origin的值。那服务器端如何设置来自多个域名的cookie通过验证呢?参考Stack Overflow上的解决方案: Access-Control-Allow-Origin Multiple Origin Domains?
Cors跨域资源共享cookie原理,参考阮大的跨域资源共享 CORS 详解
参考链接:
还是好玩的