Как изменить заголовки запроса?

Можно ли изменить заголовки объекта Request, который получено событием fetch?

Две попытки:

  1. Изменить существующие заголовки:

    self.addEventListener('fetch', function (event) {
      event.request.headers.set("foo", "bar");
      event.respondWith(fetch(event.request));
    });
    

    Не работает с Failed to execute 'set' on 'Headers': Headers are immutable.

  2. Создать новый Request объект:

    self.addEventListener('fetch', function (event) {
      var req = new Request(event.request, {
        headers: { "foo": "bar" }
      });
      event.respondWith(fetch(req));
    });
    

    Ошибка с Failed to construct 'Request': Cannot construct a Request with a Request whose mode is 'navigate' and a non-empty RequestInit.

(См. Также Как изменить заголовки ответа? )


person mjs    schedule 15.02.2016    source источник


Ответы (3)


Создание нового объекта запроса работает до тех пор, пока вы устанавливаете все параметры:

// request is event.request sent by browser here 
var req = new Request(request.url, {
    method: request.method,
    headers: request.headers,
    mode: 'same-origin', // need to set this properly
    credentials: request.credentials,
    redirect: 'manual'   // let browser handle redirects
});

Вы не можете использовать исходный mode, если он navigate (поэтому вы получили исключение), и вы, вероятно, захотите передать перенаправление обратно в браузер, чтобы он мог изменить свой URL, вместо того, чтобы позволить fetch обрабатывать его.

Убедитесь, что вы не устанавливаете тело для запросов GET - fetch это не нравится, но браузеры иногда генерируют запросы GET с телом при ответе на перенаправления из запросов POST. fetch это не нравится.

person pirxpilot    schedule 16.02.2016
comment
Вы случайно не знаете, почему mode из navigate может быть проблемой? - person mjs; 16.02.2016
comment
Шаг 12.1 fetch.spec.whatwg.org/#dom-request: если режим запроса - навигация, выбросить TypeError .. - person Marco Castelluccio; 16.02.2016
comment
Что насчет тела запроса в случае публикации? - person Michael Kapustey; 21.08.2018

Вы можете создать новый запрос на основе исходного и переопределить заголовки:

new Request(originalRequest, {
  headers: {
    ...originalRequest.headers,
    foo: 'bar'
  }
})

См. Также: https://developer.mozilla.org/en-US/docs/Web/API/Request/Request

person caisah    schedule 22.05.2019
comment
именно то, что мне было нужно! Спасибо. Я сходил с ума. - person Zibri; 18.07.2019
comment
Вы должны добавить некоторый контекст ... это решение лучше. Вы можете просто бросить event.request при новом запросе и сделать неизменяемый заголовок изменяемым: D, тогда вы можете просто настроить заголовки при работе с вновь созданным запросом. в контексте выборки это всего лишь 3 строки кода :). Также мне кажется очень надежным и устойчивым к ошибкам. - person GDY; 03.08.2020

Пробовали ли вы использовать решение, аналогичное тому, что указано в упомянутом вами вопросе (Как изменить заголовки ответа?)?

В книге Service Worker Cookbook мы вручную копируем объекты Request, чтобы сохранить их в IndexedDB (https://serviceworke.rs/request-deferrer_service-worker_doc.html). Это по другой причине (мы хотели хранить их в кэше, но мы не можем хранить запросы POST из-за https://github.com/slightlyoff/ServiceWorker/issues/693), но это должно быть применимо и к тому, что вы хотите делать.

// Serialize is a little bit convolved due to headers is not a simple object.
function serialize(request) {
  var headers = {};
  // `for(... of ...)` is ES6 notation but current browsers supporting SW, support this
  // notation as well and this is the only way of retrieving all the headers.
  for (var entry of request.headers.entries()) {
    headers[entry[0]] = entry[1];
  }
  var serialized = {
    url: request.url,
    headers: headers,
    method: request.method,
    mode: request.mode,
    credentials: request.credentials,
    cache: request.cache,
    redirect: request.redirect,
    referrer: request.referrer
  };



  // Only if method is not `GET` or `HEAD` is the request allowed to have body.
  if (request.method !== 'GET' && request.method !== 'HEAD') {
    return request.clone().text().then(function(body) {
      serialized.body = body;
      return Promise.resolve(serialized);
    });
  }
  return Promise.resolve(serialized);
}

// Compared, deserialize is pretty simple.
function deserialize(data) {
  return Promise.resolve(new Request(data.url, data));
}
person Marco Castelluccio    schedule 16.02.2016