最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to getset multiple 'Set-Cookie' Headers using Fetch API? - Stack Overflow

programmeradmin3浏览0评论

As you might know, RFC 6265 indicates that it is allowed to have multiple headers with the Set-Cookie name.

However, Fetch API doesn't allow to do that because all the methods exposed by its Headers interface (including get(), set(), append(), entries() and all the rest) have been implemented to merge the values of all the headers with the same name into a single header separated by commas.

For example, if we do this:

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');

and then we try to read the set-cookie values using get('set-cookie'), or by iterating the headers variable using entries(), we get this:

'set-cookie' : test1=v; Max-Age=0, test2=v; Max-Age=0, test3=v; Max-Age=0

Please notice that the same wrong behaviour also happens if we try to read or manipulate an existing response object having multiple headers with the same name (i.e. created by other frameworks that arguably support such allowed behavior): in other words, it seems like the Fetch API is completely unable to properly deal with such scenario.

Now, while this behavior is desired for some headers, such as Accept, the Set-Cookie header is not parsed correctly by most browsers (including Chrome and Firefox), thus resulting in cookies not being correctly set.

Is that a known bug? If that's the case, is there an usable workaround that can be used to overcome this?

As you might know, RFC 6265 indicates that it is allowed to have multiple headers with the Set-Cookie name.

However, Fetch API doesn't allow to do that because all the methods exposed by its Headers interface (including get(), set(), append(), entries() and all the rest) have been implemented to merge the values of all the headers with the same name into a single header separated by commas.

For example, if we do this:

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');

and then we try to read the set-cookie values using get('set-cookie'), or by iterating the headers variable using entries(), we get this:

'set-cookie' : test1=v; Max-Age=0, test2=v; Max-Age=0, test3=v; Max-Age=0

Please notice that the same wrong behaviour also happens if we try to read or manipulate an existing response object having multiple headers with the same name (i.e. created by other frameworks that arguably support such allowed behavior): in other words, it seems like the Fetch API is completely unable to properly deal with such scenario.

Now, while this behavior is desired for some headers, such as Accept, the Set-Cookie header is not parsed correctly by most browsers (including Chrome and Firefox), thus resulting in cookies not being correctly set.

Is that a known bug? If that's the case, is there an usable workaround that can be used to overcome this?

Share Improve this question edited Mar 18, 2024 at 10:45 VLAZ 29k9 gold badges62 silver badges83 bronze badges asked Aug 1, 2020 at 10:14 DarksealDarkseal 9,56410 gold badges83 silver badges115 bronze badges 6
  • I believe this is the only HTTP header for which it's not allowed to be merged like this. So I'm not entirely shocked that this case is not considered. Do you get separate entries when you iterate over the headers (with .entries()) – Evert Commented Aug 1, 2020 at 10:23
  • @Evert nope, as I explained above, all those methods will return the values merged as one, regardless of what the response object actually contains. To put it in other words, you always get a single (merged) Set-Cookie entry. – Darkseal Commented Aug 1, 2020 at 11:35
  • 1 Set-Cookie is sent by the server, not the client. Why do you need it in the Fetch API? – Barmar Commented Aug 4, 2020 at 14:53
  • @Barmar I've developed a CORS proxy that forwards requests to upstream and responses to clients, therefore I have to deal with HTTP responses in various ways. If you're interested, PM me and I'll send the details, however trust me - I definitely need this answer. – Darkseal Commented Aug 6, 2020 at 19:53
  • If you want to try to get the bounty, here's the code I need to fix/workaround (line 240 and below). Reading the comments should be enough to understand the issue I'm having and what I would like to obtain. – Darkseal Commented Aug 6, 2020 at 20:04
 |  Show 1 more comment

2 Answers 2

Reset to default 11 +50

This is a known "issue" with the standard. It's actually the first note of the Fetch API standard in the Headers section:

Unlike a header list, a Headers object cannot represent more than one Set-Cookie header. In a way this is problematic as unlike all other headers Set-Cookie headers cannot be combined, but since Set-Cookie headers are not exposed to client-side JavaScript this is deemed an acceptable compromise. Implementations could chose the more efficient Headers object representation even for a header list, as long as they also support an associated data structure for Set-Cookie headers.

You can read more or even raise your own issue in the spec's repo.
There are already a few issues discussing the Set-Cookie case at length though:

  • https://github.com/whatwg/fetch/issues/973
  • https://github.com/whatwg/fetch/issues/506
  • https://github.com/whatwg/fetch/issues/189
  • https://lists.w3.org/Archives/Public/www-archive/2016Jan/thread.html

You mentioned using workarounds, but this really depends on your use-case.
The note mentions using a secondary structure to handle those.
If you really want to store those cookies in a Headers object, you could add custom headers to store them:

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

Obviously, this is not an acceptable solution for the standard, but maybe your practical considerations might be in line with such a compromise.


As pointed out by this note and @Barmar in the comments, you usually use Set-Cookie from the server, not the front-end.
For instance, there's no problem setting multiple Set-Cookie with express:

test.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/`));

Terminal 1

$ node test.js
Listening on http://localhost:3000/

Terminal 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
[...]

The method getSetCookie() was added to Fetch API interface in order to address this issue. This method provides the ability to get the list of values for all Set-Cookie headers.

发布评论

评论列表(0)

  1. 暂无评论