8

Is it possible to alter the headers of a Response object, as returned by fetch()?

Suppose I want to transform a response via resFn:

self.addEventListener('fetch', function (event) {
  event.respondWith(fetch(event.request).then(resFn));
});

What should resFn() look like? One attempt:

function resFn(res) {
  res = res.clone();
  res.headers.set("foo", "bar");
  return res;
}

Fails with TypeError: Failed to execute 'set' on 'Headers': Headers are immutable.

(A separate question and answer explain how to alter the headers of a request. Given that the the Request and Response objects are surprisingly dissimilar (different properties, and their constructors take different arguments), does the same solution apply?)

Community
  • 1
  • 1
mjs
  • 63,493
  • 27
  • 91
  • 122

2 Answers2

9

This can be done by "manually" cloning the response:

function resFn(res) {
  return newResponse(res, function (headers) {
    headers.set("foo", "bar");
    return headers;
  });
}

where the newResponse() helper function is:

function newResponse(res, headerFn) {

  function cloneHeaders() {
    var headers = new Headers();
    for (var kv of res.headers.entries()) {
      headers.append(kv[0], kv[1]);
    }
    return headers;
  }

  var headers = headerFn ? headerFn(cloneHeaders()) : res.headers;

  return new Promise(function (resolve) {
    return res.blob().then(function (blob) {
      resolve(new Response(blob, {
        status: res.status,
        statusText: res.statusText,
        headers: headers
      }));
    });
  });

}

Note that newResponse() returns a Promise<Response>.

mjs
  • 63,493
  • 27
  • 91
  • 122
  • 1
    This is amazing, nowhere else have I been able to find a solution to this. What a life saver! – derpedy-doo Oct 02 '19 at 22:48
  • 4
    god it's very complicated, i thought it's just need to do something like *res.headers.set("HeaderName", "HeaderValue")* turns out headers is immutable – Adam Mudianto Sep 23 '20 at 06:32
6

The current answer is quite verbose. You can achieve the same thing by doing the following:

const newHeaders = new Headers(initialResponse.headers)
newHeaders.set('foo', 'bar')
const newResponse = new Response(initialResponse.body, {
  headers: newHeaders
})  

The initial attempt in the question was close. When you create a headers object it isn't immutable, it only becomes immutable when set on the response object.

Matt Way
  • 32,319
  • 10
  • 79
  • 85