Как получить / установить несколько заголовков Set-Cook ie с помощью Fetch API? - PullRequest
4 голосов
/ 01 августа 2020

Как вы, возможно, знаете, RF C 6265 указывает, что разрешено иметь несколько заголовков с именем Set-Cookie.

Однако Fetch API не позволяет это сделать, потому что все методы, предоставляемые его интерфейсом Headers (включая 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');

, а затем мы попытаемся прочитать set-cookie значения с использованием get('set-cookie') или путем итерации переменной headers с помощью entries(), мы получаем следующее:

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

Обратите внимание, что такое же неправильное поведение также происходит, если мы пытаемся прочитать или изменить существующий объект ответа, имеющий несколько заголовков с одинаковым именем (т.е. созданный другими фреймворками, которые, возможно, поддерживают такое разрешенное поведение): другими словами, похоже, что Fetch API полностью неспособен правильно справиться с таким сценарием.

Теперь, почему Если это поведение желательно для некоторых заголовков, таких как Accept, заголовок Set-Cookie неправильно анализируется большинством браузеров (включая Chrome и Firefox), что приводит к неправильной установке файлов cookie.

Это известная ошибка? Если это так, есть ли обходной путь, который можно использовать для решения этой проблемы?

1 Ответ

4 голосов
/ 04 августа 2020

Это известная "проблема" стандарта. Фактически это первое примечание стандарта Fetch API в разделе Headers:

В отличие от списка header, объект Headers не может представлять более одного Set-Cookie заголовок. В некотором смысле это проблематично: c, в отличие от всех других заголовков, Set-Cookie заголовки не могут быть объединены, но поскольку заголовки Set-Cookie не отображаются на стороне клиента JavaScript, это считается приемлемым компромиссом. Реализации могут выбрать более эффективное представление объекта Headers даже для списка заголовков, если они также поддерживают связанную структуру данных для Set-Cookie заголовков.

Вы можете прочитать больше или даже поднять свой вопрос в репо spe c . Тем не менее, уже есть несколько вопросов, касающихся подробного обсуждения случая Set-Cookie:

Вы упомянули обходные пути, но это действительно зависит от вашего использования -кейс. В примечании упоминается использование вторичной структуры для их обработки. Если вы действительно хотите сохранить эти файлы cookie в объекте Headers, вы можете добавить собственные заголовки для их хранения:

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

Очевидно, что это неприемлемое решение для стандарта, но, возможно, ваши практические соображения может соответствовать такому компромиссу.

Как указано в этой заметке и @Barmar в комментариях, вы обычно используете Set-Cookie с сервера, а не из внешнего интерфейса. Например, без проблем установить несколько Set-Cookie с помощью 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/`));

Терминал 1

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

Клемма 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
[...]
...