Warm tip: This article is reproduced from serverfault.com, please click

node.js-为什么未在浏览器中设置res标头中的cookie?

(node.js - Why cookie in res headers is not set in browser?)

发布于 2020-11-27 10:28:34

我在后端运行,在http://localhost:4000前端运行http://localhost:3000在服务器(快速)中,我将cors策略设置为:

  app.use( cors({
    credentials: true,
    origin: "http://localhost:3000",
  }));

但是未设置cookie。请求后

POST /graphql HTTP/1.1
Host: localhost:4000
Connection: keep-alive
Content-Length: 373
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36
content-type: application/json
Accept: */*
Origin: http://localhost:3000
Sec-Fetch-Site: same-site
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://localhost:3000/register
Accept-Encoding: gzip, deflate, br
Accept-Language: et-EE,et;q=0.9,en-US;q=0.8,en;q=0.7

我返回了带有正确的响应头(?)Set-Cookie

HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: http://localhost:3000
Vary: Origin
Access-Control-Allow-Credentials: true
Content-Type: application/json; charset=utf-8
Content-Length: 122
ETag: W/"7a-3NezKfolEhPugNDLsBCed9Xgfzk"
Set-Cookie: lirr=s%3A9JJT7_mt6W-zSWkg-DKkBmxK6O-i8bH3.1k88dMMeintjdSUMV6ig1DK5u4vgdYh4rnmtufww7nw; Path=/; Expires=Sat, 27 Nov 2021 09:31:14 GMT; HttpOnly; SameSite=Lax
Date: Fri, 27 Nov 2020 09:31:14 GMT
Connection: keep-alive
Keep-Alive: timeout=5

我尝试使用Chrome和Firefox,但均未设置Cookie。我的设置没有发现任何缺陷,标题似乎很好。我想念什么?

此外

如果让我从后端设置cookie(公开为Graphql API,可通过Graphql Playground访问),则可以通过以下req头正常工作:

POST /graphql HTTP/1.1
Host: localhost:4000
Connection: keep-alive
Content-Length: 323
accept: */*
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36
content-type: application/json
Origin: http://localhost:4000
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://localhost:4000/graphql
Accept-Encoding: gzip, deflate, br
Accept-Language: et-EE,et;q=0.9,en-US;q=0.8,en;q=0.7

据我所知,三行(按预期)有所不同:

Origin: http://localhost:4000
Sec-Fetch-Site: same-origin
Referer: http://localhost:4000/graphql

响应与前端的响应几乎相同:

HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: http://localhost:3000
Vary: Origin
Access-Control-Allow-Credentials: true
Content-Type: application/json; charset=utf-8
Content-Length: 75
ETag: W/"4b-Ud8RJ2O7ZjwpTxFNSAQi92iV20w"
Set-Cookie: lirr=s%3A9CYQjFpVwG69-ojwqlk-FJWVNC02DMJP.Prt8U5%2Bcco9ktEL27JoOkAlACGKS%2Fy1NHfgugPypl00; Path=/; Expires=Sat, 27 Nov 2021 10:32:37 GMT; HttpOnly; SameSite=Lax
Date: Fri, 27 Nov 2020 10:32:37 GMT
Connection: keep-alive
Keep-Alive: timeout=5

我不明白,为什么浏览器没有通过前端设置cookie ...

Questioner
w.k
Viewed
1
John 2020-12-01 10:06:32

服务器端检查

你的设置对我来说很好。

  app.use( cors({
    credentials: true,
    origin: "http://localhost:3000",
  }));

我建议使用一些API工具(例如POSTman)测试你的代码,该工具会默认启用CORS请求如果它与POSTman一起使用,则你的服务器端代码没有问题。

CORS + Cookie的浏览器问题

简而言之,CORS请求不过是到不同域的XMLHttpRequest。https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS

根据以下文档, https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials

此外,此标志还用于指示何时在响应中忽略cookie默认值为false来自其他域的XMLHttpRequest不能为自己的域设置cookie值,除非在发出请求之前将withCredentials设置为true通过将withCredentials设置为true获得的第三方cookie仍将遵循同源策略,因此,请求脚本无法通过document.cookie或从响应标头访问。

除非你启用它,否则浏览器将不会通过CORS request(XMLHttpRequest)接受/传输cookie。

xhr.withCredentials = true;

通过浏览器控制台的示例

//from http://localhost:3000
const xhr = new XMLHttpRequest();
const url = 'http://localhost:4000/get-cookie-url';
   
xhr.open('GET', url);
xhr.withCredentials = true; // enable browser to transfer cookies
xhr.onload = function(e){
  console.log(e)
};
xhr.send();

Cookie转移

为了说明这一点,cookie的传输类似于握手

双方都需要发起握手。如果一侧(服务器)启动而另一侧(客户端)未启动,则握手不会发生。

服务器启动Cookie传输时,

//Server response header
//Server will response with "Set-Cookie" header when browser requests
...
Set-Cookie: lirr=xxxx; ...
...

客户(浏览器)启动Cookie传输时,

//Client request header
//Client will request with "Cookie" header 
...
Cookie: lirr=xxxx; ....
...