问题描述
我正在构建一个应用程序,它将利用 ServiceWorker 和索引数据库来缓存数据并允许用户离线工作。该站点使用两个页面:index.html 和activity.html。主页将显示活动列表。选择其中一个活动时,它将其重定向到Activity.html并将所选活动传递为URL参数。该页面加载了从索引数据库中提取的特定活动的数据。
这个想法是用户在早上登录主页,然后可以离线访问他们的每个活动,而无需互联网连接。如果用户在线时打开每个活动,然后离线,则此方法有效。但是,如果他们只访问主页,然后离线,然后单击某个活动,则会收到此错误:
加载失败 ‘https://[site]/activity.html?activityid=35956087’。 ServiceWorker 向 FetchEvent.respondWith() 传递了一个承诺,即 尝试获取时因“类型错误:网络错误”而被拒绝 资源。'.
我猜我没有正确缓存某些东西,但我不知道为什么。这是 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,您别无选择,只能通过从当前属性中提取属性来创建一个新的 URL,因为以下三个原因:
-
Request
对象在设计上是不可变的 -
Request
构造函数采用Request
作为第一个参数,但不采用 URL 作为第二个参数 -
Request.clone()
方法只是创建Request
的精确副本并且不接受任何参数
这是一个 stripParameters
函数的可能通用实现,该函数克隆 Request
,同时从 URL 中剥离参数并保留其他属性(如 method
、headers
和其他):
const req = new Request("https://www.stackoverflow.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() 函数的“ignoreSearch”参数。
替换这个:
event.respondWith(caches.match(event.request)
有了这个:
event.respondWith(caches.match(event.request,{'ignoreSearch' : true})
根据文档:
ignoreSearch:一个布尔值,指定是否忽略查询 URL 中的字符串。例如,如果设置为 true ?value=bar 部分 http://example.com/?value=bar 在执行匹配时将被忽略。它 默认为 false。
此处的完整文档:https://developer.mozilla.org/en-US/docs/Web/API/Cache/match
如果您需要以任何方式实际更改请求,例如修改 URL 参数而不是在 fetch 请求中忽略它们,您将需要使用 Guerric P 的克隆请求选项。