'How to alter the headers of a Request?
Is it possible to alter the headers of the Request
object that is received by the fetch
event?
Two attempts:
Modify existing headers:
self.addEventListener('fetch', function (event) { event.request.headers.set("foo", "bar"); event.respondWith(fetch(event.request)); });
Fails with
Failed to execute 'set' on 'Headers': Headers are immutable
.Create new
Request
object:self.addEventListener('fetch', function (event) { var req = new Request(event.request, { headers: { "foo": "bar" } }); event.respondWith(fetch(req)); });
Fails with
Failed to construct 'Request': Cannot construct a Request with a Request whose mode is 'navigate' and a non-empty RequestInit.
(See also How to alter the headers of a Response?)
Solution 1:[1]
Creating a new request object works as long as you set all the options:
// 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
});
You cannot use the original mode
if it is navigate
(that's why you were getting an exception) and you probably want to pass redirection back to browser to let it change its URL instead of letting fetch
handle it.
Make sure you don't set body on GET requests - fetch does not like it, but browsers sometimes generate GET requests with the body when responding to redirects from POST requests. fetch
does not like it.
Solution 2:[2]
You can create a new request based on the original one and override the headers:
new Request(originalRequest, {
headers: {
...originalRequest.headers,
foo: 'bar'
}
})
See also: https://developer.mozilla.org/en-US/docs/Web/API/Request/Request
Solution 3:[3]
Have you tried with a solution similar to the one in the question you mention (How to alter the headers of a Response?)?
In the Service Worker Cookbook, we're manually copying Request objects to store them in IndexedDB (https://serviceworke.rs/request-deferrer_service-worker_doc.html). It's for a different reason (we wanted to store them in a Cache, but we can't store POST requests because of https://github.com/slightlyoff/ServiceWorker/issues/693), but it should be applicable for what you want to do as well.
// 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));
}
Solution 4:[4]
If future readers have a need to also delete keys in the immutable Request
/Response
headers and also want high fidelity to the immutable headers, you can effectively clone the Header
object:
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.
You can then create a new Request
and pass in your mutableHeaders
.
This is preferred to the accepted answer because if you have the need to proxy a Request
, you don't want to manually specify every possible header while including the Cloudflare, AWS, Azure, Google, etc. custom CDN headers.
Background Info
The reason why the headers are immutable or read-only in a Request
is because:
interface Request extends Body {
readonly cache: RequestCache;
readonly credentials: RequestCredentials;
readonly destination: RequestDestination;
readonly headers: Headers;
readonly integrity: string;
...
The interface for Headers
is:
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;
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | pirxpilot |
Solution 2 | Brad |
Solution 3 | Community |
Solution 4 | Drakes |