Как изменить заголовки запроса?
Можно ли изменить заголовки Request
объект, который получен fetch
событие?
Две попытки:
Изменить существующие заголовки:
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
,Создать новый
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.
(См. Также Как изменить заголовки ответа?)
4 ответа
Создание нового объекта запроса работает до тех пор, пока вы установите все параметры:
// 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
не нравится
Вы можете создать новый запрос на основе исходного и переопределить заголовки:
new Request(originalRequest, {
headers: {
...originalRequest.headers,
foo: 'bar'
}
})
Пытались ли вы найти решение, аналогичное предложенному в вопросе ( как изменить заголовки ответа?)?
В поваренной книге Service Worker мы вручную копируем объекты Request, чтобы сохранить их в IndexedDB ( https://serviceworke.rs/request-deferrer_service-worker_doc.html). Это по другой причине (мы хотели сохранить их в Cache, но мы не можем хранить 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));
}
Если у будущих читателей возникнет необходимость также удалить ключи в неизменном каталоге /
Response
заголовки, а также требуется высокая точность неизменяемых заголовков, вы можете эффективно клонировать
Header
объект:
const mutableHeaders = new Headers();
immutableheaders.forEach((value, key, parent) => mutableHeaders.set(key, value));
mutableHeaders.delete('content-encoding');
mutableHeaders.delete('vary');
mutableHeaders['host'] = 'example.com';
// etc.
Затем вы можете создать новый и передать свой
mutableHeaders
.
Это предпочтительнее принятого ответа, потому что, если вам нужно прокси-сервер, вы не хотите вручную указывать все возможные заголовки, включая пользовательские заголовки Cloudflare, AWS, Azure, Google и т. д.
Справочная информация
Причина, по которой заголовки неизменяемы или доступны только для чтения в
Request
это потому что:
interface Request extends Body {
readonly cache: RequestCache;
readonly credentials: RequestCredentials;
readonly destination: RequestDestination;
readonly headers: Headers;
readonly integrity: string;
...
Интерфейс для
Headers
является:
interface Headers {
append(name: string, value: string): void;
delete(name: string): void;
get(name: string): string | null;
has(name: string): boolean;
set(name: string, value: string): void;
forEach(callbackfn: (value: string, key: string, parent: Headers) => void, thisArg?: any): void;
}