think icon indicating copy to clipboard operation
think copied to clipboard

Ajax跨域时,如何带上目标地址需要的cookie?

Open bytemofan opened this issue 7 years ago • 1 comments

我们使用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,费多大的劲都是白搭,还是会被浏览器同源策略给阻拦。 image

服务器同时设置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

否则,浏览器还是会挡住跨域请求: image

既然Access-Control-Allow-Origin只允许单一域名, 服务器可能需要维护一个接受 Cookie 的 Origin 列表, 验证 Origin 请求头字段后直接将其设置为Access-Control-Allow-Origin的值。那服务器端如何设置来自多个域名的cookie通过验证呢?参考Stack Overflow上的解决方案: Access-Control-Allow-Origin Multiple Origin Domains?

Cors跨域资源共享cookie原理,参考阮大的跨域资源共享 CORS 详解

参考链接:

bytemofan avatar Aug 25 '17 11:08 bytemofan

还是好玩的

tianxianglan avatar Apr 04 '19 08:04 tianxianglan