在 Service Worker 通过网络发送之前,如何从 URL 中删除搜索参数?

How do I strip the search params from an URL before sending it over the network in a Service Worker?

我正在构建一个应用程序,它将利用 ServiceWorker 和 Indexed DB 来缓存数据并允许用户离线工作。该站点使用两个页面:index.html 和 activity.html。主页将显示活动列表。选择这些活动之一后,它会重定向到 activity.html 并将所选 activity 作为 URL 参数传递。该页面加载了从特定 activity.

的索引数据库中提取的数据

这个想法是用户在早上登录主页,然后可以离线并在没有互联网连接的情况下访问他们的每个活动。如果用户在线时打开每个 activity,然后离线,则此方法有效。但是,如果他们只访问主页,然后下线,然后单击 activity,他们会收到此错误:

Failed to load ‘https://[site]/activity.html?activityid=35956087’. A ServiceWorker passed a promise to FetchEvent.respondWith() that rejected with ‘TypeError: NetworkError when attempting to fetch resource.’.

我猜我没有正确缓存某些内容,但我不明白为什么。这是 serviceworker.js:

var urlsToCache = [
    '/[webapp]/activity.html', //Web app title removed for posting online
    '/[webapp]/index.html',
    ...
];

self.addEventListener('install', function(event) {
  // Perform install steps
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(function(cache) {
       console.log('Service Workers opened cache');
        return cache.addAll(urlsToCache);
      })
  );
});


self.addEventListener('activate', function(event) {
  event.waitUntil(function(){
    
  }
  );
});

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request)
      .then(function(response) {
        // Cache hit - return response
        if (response) {
          return response;
        }

        return fetch(event.request).then(
          function(response) {
            // Check if we received a valid response
            if(!response || response.status !== 200 || response.type !== 'basic') {
              return response;
            }

            // Copied from another source:
        // IMPORTANT: Clone the response. A response is a stream
            // and because we want the browser to consume the response
            // as well as the cache consuming the response, we need
            // to clone it so we have two streams.
            var responseToCache = response.clone();

            caches.open(CACHE_NAME)
              .then(function(cache) {
                cache.put(event.request, responseToCache);
              });

            return response;
          }
        );
      })
    );
});

编辑:我确定问题是由 URL 参数引起的(IMO,这完全是荒谬的)。从请求中删除 URL 参数的正确方法是什么?

为了更改 Request 的 URL,您别无选择,只能通过从当前对象中提取属性来创建一个新对象,因为以下三个原因:

  • Request 对象在设计上是不可变的
  • Request 构造函数将 Request 作为第一个参数,但不将 URL 作为第二个参数
  • Request.clone() 方法只是创建 Request 的精确副本并且不带任何参数

这是一个 stripParameters 函数的可能通用实现,它克隆 Request 同时从 URL 中剥离参数并保留其他属性(如 methodheaders 等):

const req = new Request("https://www.whosebug.com/path?param=foo", {
  method: "POST",
  headers: { "Authorization": "token" }
});

function stripParameters(request) {
  const keys = Object.entries(
    Object.getOwnPropertyDescriptors(Request.prototype)
  )
    .filter(([, value]) => !value.writable)
    .map(([key]) => key);
  const extractedProperties = keys.reduce(
    (acc, cur) => ({ ...acc, [cur]: request[cur] }),
    {}
  );
  const url = new URL(extractedProperties.url);
  const strippedUrl = url.href.replace(url.search, "");
  return new Request(strippedUrl, extractedProperties);
}

console.log(stripParameters(req));

虽然 Guerric P 的克隆响应选项可能会起作用,但忽略 URL 参数的最简单选项(我后来发现并成功实施)是使用 cache.match() 函数。

替换为:

  event.respondWith(caches.match(event.request)

有了这个:

event.respondWith(caches.match(event.request, {'ignoreSearch' : true})

根据文档:

ignoreSearch: A Boolean that specifies whether to ignore the query string in the URL. For example, if set to true the ?value=bar part of http://example.com/?value=bar would be ignored when performing a match. It defaults to false.

这里有完整的文档:https://developer.mozilla.org/en-US/docs/Web/API/Cache/match

如果您需要以任何方式实际更改请求,例如修改 URL 参数而不是在获取请求中忽略它们,您将需要使用 Guerric P 的克隆请求选项。