Хук или обратный вызов для записи значения заголовка перед первым байтом тела в express.js - PullRequest
0 голосов
/ 14 марта 2019

В некоторых глобальных промежуточных программах уровня приложений в express.js (4.16.4) и node.js (10.15.1) я хотел бы записать cookie в заголовок при самой последней возможности, прежде чем какое-либо промежуточное ПО запишет первый байттела к объекту ответа.

Например, представив событие beforeWriteBody для объекта Response, мы могли бы сделать что-то вроде этого:

res.on('beforeWriteResponseBody', res => {
    res.cookie('key', 'value');
});

Признавая, чтоэто событие также могут прослушиваться другими получателями, и они могут писать заголовки после этой функции, тем не менее, это было бы очень полезно для меня, поскольку это могло бы помочь избежать записи этого значения cookie несколько раз, так как я заранее не знаю, где вВ конвейере значение cookie может быть обновлено до того, как будет записан фактический первый байт тела ответа.

Асинхронизация будет в порядке, например, если любой слушатель этого события попытается записать байты в тело ответа, ивсе еще другие слушатели в списке, который будет вызван позже, этот слушатель, пишущий на теле, мог быть приостановлен, а остальныеМожно было вызвать вызывающих слушателей, затем выполнение вернулось к автору тела (хотя порядок выполнения мог бы быть сложным, если он был просто принудительно установлен как порядок присоединения слушателя, я все еще думаю, что это может быть разумно).

Я хочу сохранить что-то в cookie, но с возможностью изменять его несколько раз, не записывая несколько повторяющихся заголовков Set-Cookie, но это происходит надежно, независимо от того, какой ответ был написан, даже res.redirect(), например.

Глядя на исходный код express.js, я вижу возможную точку, в которой можно копаться, `res.send () в response.js .

После того, как он заглянулнемного, похоже, мой beforeWriteResponseBody будет вызываться перед первым действием узла request.end.

Я вижу, что в узле есть события, которые близки к тому, что я хочу,например, finish, который срабатывает после вызова end.Но мне нужно событие, которое срабатывает до вызова res.write или res.end (или после того, как они были вызваны, но до того, как они выполнят какую-либо работу).

Ответы [ 2 ]

0 голосов
/ 03 апреля 2019

Нет необходимости ждать до последней минуты, чтобы написать заголовки.Каждый раз, когда вы захотите написать заголовки, вы можете просмотреть существующие и удалить все, что вам не нужно.Это дает вам последний шанс убедиться, что заголовки верны, без добавления в ответ нескольких копий заголовка.

Это работает, даже если есть заголовки с тем же именем, которые вы не делаетехочу коснуться.

Вот очень грубая реализация того, как это может работать:

const removeUnsentHeaderFromResponseHeaders = (res, headerName, exclusionFilter) => {
  let headerValues = res.get(headerName);
  if (!headerValues) {
    return;
  }
  if (!Array.isArray(headerValues)) {
    headerValues = [headerValues];
  }
  res.header(headerName, headerValues.filter(value => !exclusionFilter(value)));
};

А вот пример использования:

// We want to set header 'My-Header', which can be set multiple times
// but also want to remove any that I've already set during this request.
// The ones my code has already set will contain `my-special-flag`.

removeUnsentHeaderFromResponseHeaders(
    res,
    'My-Header',
    headerValue => headerValue.includes('my-special-flag')
);
res.set('My-Header', 'The full my-special-flag value that should overwrite');

Просто делайте это каждый разВы устанавливаете My-Header и будете избегать отправки лишних, бесполезных значений заголовка в ответе.

0 голосов
/ 14 марта 2019

Express не поддерживает перехваты / обратные вызовы в нужной форме.

В целом, это плохо для тебя. JS позволяет вам легко перезаписать любую функцию, в этом случае вы должны сделать это так:

var app = express();

let _end = express.response.end
express.response.send = function() {
    if(!this.headersSent)
        console.log('can overwrite')
    _end.apply(this, arguments)
}

Если я не ошибаюсь, вы можете использовать headersSent, в противном случае вам придется позаботиться об одноразовых методах вызова, например, добавив флаг к res.

...