【问题标题】:How to alter the headers of a Request?如何更改请求的标头?
【发布时间】:2016-02-15 23:25:42
【问题描述】:

是否可以更改fetch 事件接收到的Request 对象的标头?

两次尝试:

  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. 失败

(另见How to alter the headers of a Response?

【问题讨论】:

    标签: javascript service-worker


    【解决方案1】:

    只要您设置了所有选项,就可以创建一个新的请求对象:

    // 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
    });
    

    如果原来的modenavigate(这就是您遇到异常的原因),则您不能使用原始mode,并且您可能希望将重定向传递回浏览器以使其更改其URL,而不是让fetch 处理它.

    确保您没有在 GET 请求上设置正文 - fetch 不喜欢它,但浏览器有时会在响应来自 POST 请求的重定向时生成带有正文的 GET 请求。 fetch 不喜欢。

    【讨论】:

    • 你知道为什么navigate 中的mode 会是个问题吗?
    • fetch.spec.whatwg.org/#dom-request 的第 12.1 步:“如果请求的模式是“导航”,则抛出 TypeError。
    • 在post的情况下请求正文呢?
    【解决方案2】:

    您可以在原始请求的基础上创建一个新请求并覆盖标头:

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

    另请参阅:https://developer.mozilla.org/en-US/docs/Web/API/Request/Request

    【讨论】:

    • 正是我需要的!谢谢。我快疯了。
    • 你应该添加一些上下文......这个解决方案是优越的。您可以在新请求中抛出 event.request 并使不可变标头“可变”:D 然后您可以调整标头以处理新创建的请求。在获取上下文中,这只是 3 行代码:)。对我来说似乎也非常健壮和防错。
    【解决方案3】:

    您是否尝试过类似于您提到的问题 (How to alter the headers of a Response?) 中的解决方案?

    在 Service Worker Cookbook 中,我们手动复制 Request 对象以将它们存储在 IndexedDB (https://serviceworke.rs/request-deferrer_service-worker_doc.html) 中。这是出于不同的原因(我们想将它们存储在缓存中,但由于https://github.com/slightlyoff/ServiceWorker/issues/693,我们无法存储 POST 请求),但它应该也适用于您想做的事情。

    // 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));
    }
    

    【讨论】:

      【解决方案4】:

      如果未来的读者还需要删除不可变的 Request/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.
      

      然后您可以创建一个新的Request 并传入您的mutableHeaders

      这比已接受的答案更受欢迎,因为如果您需要代理 Request,您不想手动指定每个可能的标头,同时包括 Cloudflare、AWS、Azure、Google 等自定义 CDN 标头.


      背景资料

      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;
      }
      

      【讨论】:

        猜你喜欢
        • 2018-06-27
        • 1970-01-01
        • 2016-11-23
        • 2015-07-27
        • 2017-09-17
        • 1970-01-01
        • 2021-01-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多