我可以在服务工作者中服务之前编辑缓存的 index.html 吗?
Can I edit cached index.html before serving in service worker?
我正在开发的 webapp 是通过 post 在 webview 中打开的。 post 正文参数(上下文用户输入)被插入到 index.html 中。
所以重复加载失败是因为缺少上下文输入。
官方文档说没办法。它说您现在所能做的就是首先进入网络并启用导航预加载。
(https://developers.google.com/web/tools/workbox/modules/workbox-navigation-preload ----------
"This feature is intended to reduce navigation latency for developers who can't precache their HTML......")
因此,我正在寻找一种在使用前编辑缓存 index.html 的方法。我想将 post 正文参数插入到 index.html 中。我找不到任何关于编辑缓存的文档。因此,来自社区的任何 help/inputs 都将不胜感激。
Workbox !== 服务工作者。 Workbox 建立在 service worker 之上,但原始 service worker 让您可以完全控制请求和响应,因此您几乎可以做任何您想做的事情。
编辑回复
以下是更改回复文本的方法:
addEventListener('fetch', event => {
event.respondWith(async function() {
// Get a cached response:
const cachedResponse = await caches.match('/');
// Get the text of the response:
const responseText = await cachedResponse.text();
// Change it:
const newText = responseText.replace(/Hello/g, 'Goodbye');
// Serve it:
return new Response(newText, cachedResponse);
}());
});
这里有一个潜在的性能问题,您最终将完整的响应加载到内存中,并在提供第一个字节之前进行替换工作。稍加努力,你可以用流式的方式进行替换:
function streamingReplace(find, replace) {
let buffer = '';
return new TransformStream({
transform(chunk, controller) {
buffer += chunk;
let outChunk = '';
while (true) {
const index = buffer.indexOf(find);
if (index === -1) break;
outChunk += buffer.slice(0, index) + replace;
buffer = buffer.slice(index + find.length);
}
outChunk += buffer.slice(0, -(find.length - 1));
buffer = buffer.slice(-(find.length - 1));
controller.enqueue(outChunk);
},
flush(controller) {
if (buffer) controller.enqueue(buffer);
}
})
}
addEventListener('fetch', event => {
const url = new URL(event.request.url);
if (!(url.origin === location.origin && url.pathname === '/sw-content-change/')) return;
event.respondWith((async function() {
const response = await fetch(event.request);
const bodyStream = response.body
.pipeThrough(new TextDecoderStream())
.pipeThrough(streamingReplace('Hello', 'Goodbye'))
.pipeThrough(new TextEncoderStream());
return new Response(bodyStream, response);
})());
});
Here's a live demo of the above.
获取响应的 POST 参数
您需要的另一部分是获取响应的 POST 正文:
addEventListener('fetch', event => {
event.respondWith(async function() {
if (event.request.method !== 'POST') return;
const formData = await event.request.formData();
// Do whatever you want with the form data…
console.log(formData.get('foo'));
}());
});
API 见 MDN page for FormData
。
我正在开发的 webapp 是通过 post 在 webview 中打开的。 post 正文参数(上下文用户输入)被插入到 index.html 中。
所以重复加载失败是因为缺少上下文输入。
官方文档说没办法。它说您现在所能做的就是首先进入网络并启用导航预加载。 (https://developers.google.com/web/tools/workbox/modules/workbox-navigation-preload ---------- "This feature is intended to reduce navigation latency for developers who can't precache their HTML......")
因此,我正在寻找一种在使用前编辑缓存 index.html 的方法。我想将 post 正文参数插入到 index.html 中。我找不到任何关于编辑缓存的文档。因此,来自社区的任何 help/inputs 都将不胜感激。
Workbox !== 服务工作者。 Workbox 建立在 service worker 之上,但原始 service worker 让您可以完全控制请求和响应,因此您几乎可以做任何您想做的事情。
编辑回复
以下是更改回复文本的方法:
addEventListener('fetch', event => {
event.respondWith(async function() {
// Get a cached response:
const cachedResponse = await caches.match('/');
// Get the text of the response:
const responseText = await cachedResponse.text();
// Change it:
const newText = responseText.replace(/Hello/g, 'Goodbye');
// Serve it:
return new Response(newText, cachedResponse);
}());
});
这里有一个潜在的性能问题,您最终将完整的响应加载到内存中,并在提供第一个字节之前进行替换工作。稍加努力,你可以用流式的方式进行替换:
function streamingReplace(find, replace) {
let buffer = '';
return new TransformStream({
transform(chunk, controller) {
buffer += chunk;
let outChunk = '';
while (true) {
const index = buffer.indexOf(find);
if (index === -1) break;
outChunk += buffer.slice(0, index) + replace;
buffer = buffer.slice(index + find.length);
}
outChunk += buffer.slice(0, -(find.length - 1));
buffer = buffer.slice(-(find.length - 1));
controller.enqueue(outChunk);
},
flush(controller) {
if (buffer) controller.enqueue(buffer);
}
})
}
addEventListener('fetch', event => {
const url = new URL(event.request.url);
if (!(url.origin === location.origin && url.pathname === '/sw-content-change/')) return;
event.respondWith((async function() {
const response = await fetch(event.request);
const bodyStream = response.body
.pipeThrough(new TextDecoderStream())
.pipeThrough(streamingReplace('Hello', 'Goodbye'))
.pipeThrough(new TextEncoderStream());
return new Response(bodyStream, response);
})());
});
Here's a live demo of the above.
获取响应的 POST 参数
您需要的另一部分是获取响应的 POST 正文:
addEventListener('fetch', event => {
event.respondWith(async function() {
if (event.request.method !== 'POST') return;
const formData = await event.request.formData();
// Do whatever you want with the form data…
console.log(formData.get('foo'));
}());
});
API 见 MDN page for FormData
。