仅限Chrome(服务工作者):'...重定向响应用于重定向模式不是"跟随"的请求

Nat*_*gan 5 javascript google-chrome service-worker fetch-api

当我在Chrome中刷新(或离线)时,我会收到"无法访问此站点",并且以下内容已登录到控制台:The FetchEvent for "http://localhost:8111/survey/174/deployment/193/answer/offline/attendee/240/" resulted in a network error response: a redirected response was used for a request whose redirect mode is not "follow"..当我在Firefox中刷新时,一切正常.有人可以解释为什么会这样吗?

这是我简化的SW.

importScripts("/static/js/libs/idb.js")

var CACHE_NAME = "upshot-cache-version3"
var urlsToCache = [...]

self.addEventListener("install", event => {
  event.waitUntil(
    caches
      .open(CACHE_NAME)
      .then(cache => {
        urlsToCache.map(url => cache.add(url))
      })
  )
})

self.addEventListener("activate", event => {
  clients.claim()
})

self.addEventListener('fetch', event => {
  event.respondWith(
    caches
      .match(event.request)
      .then(response => {

        if (response) {
          return response
        }

        var fetchRequest = event.request.clone()

        return fetch(fetchRequest).then(response => {
          if (!response || response.status !== 200 || response.type !== 'basic') {
            return response
          }
          var responseToCache = response.clone()
          caches.open(CACHE_NAME).then(cache => cache.put(event.request, responseToCache))
          return response
        })

      })
  )
})
Run Code Online (Sandbox Code Playgroud)

Jef*_*ick 11

这是由于围绕可用于满足导航的哪种响应的安全限制的(相对)最近的变化.它应该适用于所有支持服务工作者的浏览器(例如今天的Chrome和Firefox),但是你可能正在使用过时的Firefox版本进行测试.

有关更改内容的背景信息可以在此问题跟踪器条目中找到,并且还有更多关于导致基础规范的决策背景.

在修改服务工作者以处理安全限制方面,如果您当前正在响应HTTP 30x重定向到不同URL的某些URL的导航请求,则需要注意不要直接存储重定向的响应在缓存中.

您可以通过检查是否response.redirectedtrue,以及如果是,使用代码沿着这一行(改编自Workbox项目)来创建响应的"干净"副本,然后可以将其存储在缓存中,从而判断给定响应是否被重定向:

function cleanResponse(response) {
  const clonedResponse = response.clone();

  // Not all browsers support the Response.body stream, so fall back to reading
  // the entire body into memory as a blob.
  const bodyPromise = 'body' in clonedResponse ?
    Promise.resolve(clonedResponse.body) :
    clonedResponse.blob();

  return bodyPromise.then((body) => {
    // new Response() is happy when passed either a stream or a Blob.
    return new Response(body, {
      headers: clonedResponse.headers,
      status: clonedResponse.status,
      statusText: clonedResponse.statusText,
    });
  });
}
Run Code Online (Sandbox Code Playgroud)