CORS 跨域发送 Cookie
在 Web 页面中可以随意地载入跨域的图片、视频、样式等资源, 但 AJAX 请求通常会被浏览器应用同源安全策略,禁止获取跨域数据,以及限制发送跨域请求。 虽然 有多种方法利用资源标签进行跨域,但能够进行的数据交互非常有限。 在 2014 年 W3C 发布了 CORS Recommendation 来允许更方便的跨域资源共享。 默认情况下浏览器对跨域请求不会携带 Cookie,但鉴于 Cookie 在身份验证等方面的重要性, CORS 推荐使用额外的响应头字段来允许跨域发送 Cookie。
客户端代码
在 open
XMLHttpRequest 后,设置 withCredentials
为 true
即可让该跨域请求携带 Cookie。
注意携带的是目标页面所在域的 Cookie。
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.withCredentials = true;
xhr.send();
如果你在使用 jQuery,可以通过 xhrFields
来设置:
$.ajax({
url: a_cross_domain_url,
xhrFields: {
withCredentials: true
}
});
如果你在使用 Zepto,抱歉没有办法。因为 Zepto 会在 open
之前设置 withCredentials
。
根据 WHATWG 的 XHR 标准 在 open
之后设置是不合法的,
虽然多数浏览器不抛出错误但仍然不会携带 Cookie。
True when user credentials are to be included in a cross-origin request. False when they are to be excluded in a cross-origin request and when cookies are to be ignored in its response. Initially false. When set: throws an InvalidStateError exception if state is not unsent or opened, or if the send() flag is set. – WHATWG XMLHttpRequest
Access-Control-Allow-Credentials
只设置客户端当然是没用的,还需要目标服务器接受你跨域发送的 Cookie。 否则会被浏览器的同源策略挡住:
服务器同时设置 Access-Control-Allow-Credentials
响应头为 "true"
,
即可允许跨域请求携带 Cookie。
Access-Control-Allow-Origin
除了 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
既然 Access-Control-Allow-Origin
只允许单一域名,
服务器可能需要维护一个接受 Cookie 的 Origin 列表,
验证 Origin
请求头字段后直接将其设置为 Access-Control-Allow-Origin
的值。
(这一实践来自 Stackoverflow)
值得注意的是在 CORS 请求被重定向后 Origin
头字段会被置为 null
。
此时可以选择从 Referer
头字段计算得到 Origin
。
在正确配置的情况下,在 Chrome Network 就可以看到 Cookie 请求头被跨域发送了
(注意 Host
和 Referer
不同域,但仍然带了 Cookie
):
Accept:*/*
Accept-Encoding:gzip, deflate, sdch, br
Accept-Language:zh-CN,zh;q=0.8,en;q=0.6,nl;q=0.4,zh-TW;q=0.2,fr;q=0.2,de;q=0.2,ja;q=0.2
Connection:keep-alive
Cookie:auhtor:harttle; _gat=1; _ga=GA1.1.221305049.1482947002
Host:dest.com:4001
Origin:http://index.com:4001
Referer:http://index.com:4001/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36
服务器端代码
const express = require('express');
var app = express();
app.get('/specific-allow-origin-with-credentials', (req, res) => {
res.set({
'Access-Control-Allow-Origin': 'http://index.com: 4001',
'Access-Control-Allow-Credentials': true
});
res.status(200).end('I got your cookie: ' + req.headers.cookie);
});
app.listen(4001, () => console.log('listening to 4001'));
完整的 Demo 可以从 harttle/cors-demo 获取。
本文采用 知识共享署名 4.0 国际许可协议(CC-BY 4.0)进行许可,转载注明来源即可: https://harttle.land/2016/12/28/cors-with-cookie.html。如有疏漏、谬误、侵权请通过评论或 邮件 指出。