使用 CORS 请求设置 Cookie
Posted
技术标签:
【中文标题】使用 CORS 请求设置 Cookie【英文标题】:Setting Cookies with CORS requests 【发布时间】:2016-07-21 19:06:34 【问题描述】:我这几天一直在尝试解决这个问题。在 CORS 请求上设置 cookie。我看过相互矛盾的文章和答案,有人说只要 XHR 请求将 withCredentials
设置为 true,并且服务器发送适当的标头,浏览器就应该尊重 Set-Cookie
标头。但是,在我的测试中,情况并非如此。
示例代码:
index.js(Node.js 服务器)
const http = require('http');
const fs = require('fs');
// Pretty colors
const colors =
purple: '\033[95m',
orange: '\033[93m',
blue: '\033[97m',
underline: '\033[4m',
bold: '\033[1m',
reset: '\033[0m'
const server = http.createServer(function (req, res)
//Console logs to verify what's getting hit.
console.log(colors.purple + colors.underline + 'Hit it!' + colors.reset);
console.log(colors.orange + colors.bold + 'url:' + colors.reset, req.url);
if (/\/cookie/.test(req.url))
console.log(colors.blue + 'We need to cook(ie) Jesse\n' + colors.reset);
// Generate a random string in a rather convoluted way.
var randomStr = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(36) +
Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(36) +
Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(36);
randomStr = new Buffer(randomStr.toString(), 'binary').toString('base64');
// All .dev domains pointed to localhost via dnsmasq, though a hosts file
// Update should also do the trick.
res.writeHead(200,
'Set-Cookie': 'ajaxTestCookie=cookie' + randomStr + '; Domain=.example.dev; HttpOnly',
'Access-Control-Allow-Origin': 'http://example.dev:3999',
'Access-Control-Allow-Credentials': 'true',
'Access-Control-Allow-Methods': 'GET, POST',
'Access-Control-Allow-Headers': 'Content-Type, Set-Cookie, *'
);
return res.end('OK!');
console.log(colors.blue + 'We\'re having fun at the html!\n' + colors.reset);
// Send out html file.
fs.readFile('./cookies.html', function (err, data)
if (err)
res.writeHead(500);
return res.end('Failure to launch!');
res.end(data.toString());
);
);
server.listen(3999);
cookies.html
<html>
<head>
<title>Cookie Test</title>
</head>
<body>
<button class="getCookie">Get Cookies!</button>
<script>
(function()
document.querySelector(".getCookie").addEventListener("click", function(e)
console.log("test");
var req = new XMLHttpRequest();
req.open("GET", "http://localhost:3999/cookie", true);
req.onload = function()
console.log(req.responseText);
;
req.withCredentials = true;
req.send();
);
());
</script>
</body>
</html>
我已尝试在 Firefox 开发者版和 Chrome 上对此进行测试,除非直接访问该页面,否则不会设置 cookie。
为了让 cookie 处理 CORS 请求,我有什么遗漏吗?
【问题讨论】:
我认为,服务器(而不是客户端)必须设置 cookie 才能使其工作。否则你可以在任何地方设置 cookie。 你的跨域请求,如果它在响应中设置cookies,将会为它自己的域设置cookies,而不是你的。 @PoulBak 我应该指定index.js
是一个节点文件,展示我用来测试它的服务器。所以是服务器设置了cookie。
@Pointy 在 CORS 请求中发回的 cookie 上是否忽略了 Domain
参数?还是 Domain
参数仅限于同源?
域绝对是服务器自己的域,不能设置第三方cookie,即使是CORS也不行。
【参考方案1】:
不是很明显的是服务器设置的 cookie,至少在 CORS 请求中,并且可能(可能)在所有请求中都被限制在与服务器相同的域中。
index.js(Node.js 服务器)
const http = require('http');
const fs = require('fs');
// Pretty colors
const colors =
purple: '\033[95m',
orange: '\033[93m',
blue: '\033[97m',
underline: '\033[4m',
bold: '\033[1m',
reset: '\033[0m'
const server = http.createServer(function (req, res)
//Console logs to verify what's getting hit.
console.log(colors.purple + colors.underline + 'Hit it!' + colors.reset);
console.log(colors.orange + colors.bold + 'url:' + colors.reset, req.url);
if (/\/cookie/.test(req.url))
console.log(colors.blue + 'We need to cook(ie) Jesse\n' + colors.reset);
// Generate a random string in a rather convoluted way.
var randomStr = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(36) +
Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(36) +
Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(36);
randomStr = new Buffer(randomStr.toString(), 'binary').toString('base64');
// All .dev domains pointed to localhost via dnsmasq, though a hosts file
// Update should also do the trick.
res.writeHead(200,
'Set-Cookie': 'ajaxTestCookie=cookie' + randomStr + '; domain=.example.dev; HttpOnly',
'Access-Control-Allow-Origin': 'http://example.dev:3999',
'Access-Control-Allow-Credentials': 'true',
'Access-Control-Allow-Methods': 'GET, POST',
'Access-Control-Allow-Headers': 'Content-Type, Set-Cookie, *'
);
return res.end('OK!');
console.log(colors.blue + 'We\'re having fun at the HTML!\n' + colors.reset);
// Send out html file.
fs.readFile('./cookies.html', function (err, data)
if (err)
res.writeHead(500);
return res.end('Failure to launch!');
res.end(data.toString());
);
);
server.listen(3999); // api.example.dev:3999, for example
cookies.html
<html>
<head>
<title>Cookie Test</title>
</head>
<body>
<button class="getCookie">Get Cookies!</button>
<script>
(function()
document.querySelector(".getCookie").addEventListener("click", function(e)
console.log("test");
var req = new XMLHttpRequest();
// Request succeeds, but cookie will not be set!
// req.open("GET", "http://localhost:3999/cookie", true);
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// This line, however, will work, assuming this page is on
// the same domain, or a subdomain of the same domain.
// (For example test.example.dev and api.example.dev)
// As long as the Access-Control-Allow-Origin Header is
// properly set to allow the domain.
req.open("GET", "http://api.example.dev:3999/cookie", true);
req.onload = function()
console.log(req.responseText);
;
req.withCredentials = true;
req.send();
);
());
</script>
</body>
【讨论】:
以上是关于使用 CORS 请求设置 Cookie的主要内容,如果未能解决你的问题,请参考以下文章
Firefox 未设置通过 XHR CORS 请求接收的 Cookie
hls.js CORS 使用 AWS Cloudfront 的 Cookie 问题
带有域字段的 CORS cookie 仅在使用 jQuery AJAX 的 Firefox 中设置
Set-cookie 不适用于 Dot net Core 3.1 中的跨站点请求/响应和 React 设置同站点 cookie 和/或 CORS 问题