如何使用 Fetch API 获取/设置多个“Set-Cookie”标头?

Dar*_*eal 8 javascript cookies fetch response-headers fetch-api

您可能知道,RFC 6265表明允许有多个带有该Set-Cookie名称的标头。

然而,提取API不允许这样做,因为所有的暴露的方法接口(包括get()set()append()entries()和所有其余的)已实施的所有具有相同名称的头的值合并成一个头分离用逗号。

例如,如果我们这样做:

var headers = new Headers();
headers.append('content-type', 'text/plain');
headers.append('set-cookie', 'test1=v; Max-Age=0');
headers.append('set-cookie', 'test2=v; Max-Age=0');
headers.append('set-cookie', 'test3=v; Max-Age=0');
Run Code Online (Sandbox Code Playgroud)

然后我们尝试使用 读取set-cookieget('set-cookie'),或者通过headers使用迭代变量entries(),我们得到:

'set-cookie' : test1=v; Max-Age=0, test2=v; Max-Age=0, test3=v; Max-Age=0
Run Code Online (Sandbox Code Playgroud)

请注意,如果我们尝试读取或操作具有多个同名标头的现有响应对象(即由可以说支持此类允许行为的其他框架创建),也会发生相同的错误行为:换句话说,似乎Fetch API是完全无法妥善处理这种情况。

现在,虽然这种行为所需的一些报头,如Accept,该Set-Cookie标题不正确地被大多数浏览器(包括铬和Firefox)解析,从而导致不正确设置的cookie。

这是一个已知的错误吗?如果是这种情况,是否有可用的解决方法来克服这个问题?

Jer*_*ska 7

这是标准的一个已知“问题”。其实是小节中Fetch API标准的第一个注解Headers

header列表不同,一个Headers对象不能表示多个Set-Cookie标题。在某种程度上,这是有问题的,因为与所有其他标Set-Cookie头不同,标头无法组合,但由于Set-Cookie标头不会暴露给客户端 JavaScript,因此这被认为是可以接受的折衷方案。实现可以选择更有效的 Headers 对象表示,即使对于标题列表,只要它们还支持Set-Cookie标题的关联数据结构。

您可以在规范的 repo 中阅读更多内容,甚至提出您自己的问题。
不过,已经有几个问题在详细讨论Set-Cookie此案:

您提到使用变通方法,但这实际上取决于您的用例。
该注释提到使用二级结构来处理这些。
如果您真的想将这些 cookie 存储在一个Headers对象中,您可以添加自定义标头来存储它们:

new Headers([
  ['X-MyOwn-Set-Cookie-1', 'cookie1=value1'],
  ['X-MyOwn-Set-Cookie-2', 'cookie2=value2']
]);
Run Code Online (Sandbox Code Playgroud)

显然,这不是标准可接受的解决方案,但也许您的实际考虑可能符合这种妥协。


正如本说明和评论中的@Barmar 所指出的,您通常Set-Cookie从服务器而不是前端使用。
举例来说,有没有问题,设置多个Set-Cookie具有express

测试.js

const express = require('express');

const app = express();

const cookies = [
  { key: 'cookie1', value: 'value1' },
  { key: 'cookie2', value: 'value2' },
];

app.get('*', (req, res) => {
  console.log(req.url);
  for (const { key, value } of cookies) {
    res.cookie(key, value, { expires: new Date(Date.now() + 1000 * 60), httpOnly: true });
  }
  res.status(200).send('Success');
});

app.listen(3000, () => console.log(`Listening on http://localhost:3000/`));
Run Code Online (Sandbox Code Playgroud)

1号航站楼

$ node test.js
Listening on http://localhost:3000/
Run Code Online (Sandbox Code Playgroud)

2 号航站楼

$ curl -v http://localhost:3000/
[...]
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Set-Cookie: cookie1=value1; Path=/; Expires=Tue, 04 Aug 2020 19:45:53 GMT; HttpOnly
< Set-Cookie: cookie2=value2; Path=/; Expires=Tue, 04 Aug 2020 19:45:53 GMT; HttpOnly
< Content-Type: text/html; charset=utf-8
[...]
Run Code Online (Sandbox Code Playgroud)

  • 感谢您的解释,它确实为我已经从 Google 中挖掘到的内容添加了一些内容。正如您通过阅读我给@Barman的答案所看到的,我需要找到一个合适的解决方法,可以被最常见的浏览器(Chrome、Firefox、IE、Edge、Safari)接受,因为我正在研究“无服务器” CORS 代理(托管在 Cloudflare Worker 中)旨在将 HTTP 请求转发到上游,并将 HTTP 响应转发到客户端 - 因此需要使用多个 `Set-Cookie` 实例“重建”有效的标头列表,以便以正确的方式向客户端提供数据方式。 (2认同)

mic*_*ael 5

Fetch API 接口中添加了getSetCookie()方法来解决此问题。此方法提供获取所有标头的值列表的能力Set-Cookie