在 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 中剥离参数并保留其他属性(如 method
, headers
等):
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 的克隆请求选项。
我正在构建一个应用程序,它将利用 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 中剥离参数并保留其他属性(如 method
, headers
等):
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 的克隆请求选项。