在服务工作者中,我想将HTML注入HTTP响应主体:
在返回缓存的HTML响应时,我想在{1}}之前和之后流式传输原始响应时注释<html>
元素(例如将<html lang="en">
转换为<html data-origin="cache" lang="en">
)。
我尝试过根据Jake Archibald's streams fawning实现此功能,但无法正常工作。在下面的例子中,我想象injectHTML
返回一个转换原始流的一部分的包装器 - 但我不知道如何到达那里。任何建议将不胜感激。
addEventListener("fetch", async event => {
let request = event.request;
if(request.method !== "GET" ||
!request.headers.get("Accept").includes("text/html")) {
return;
}
let response = await fetch(request);
let stream = injectHTML(response.body);
response = new Response(stream);
event.respondWith(response);
});
答案 0 :(得分:1)
杰克的streams explainer及其中包含的示例是一个很好的起点。
最相关的例子就是那个...... replaces "cloud" with "butt"。
服务工作者代码,以及一些警告can be found on GitHub。
为了完整起见,这里是处理替换的相关服务工作者代码,但我建议在上下文中查看完整的源代码。
function replaceResponse(response, bufferSize, match, replacer) {
const reader = response.body.getReader();
const encoder = new TextEncoder();
const decoder = new TextDecoder();
let bufferStr = '';
const stream = new ReadableStream({
pull: controller => {
return reader.read().then(result => {
if (result.done) {
controller.enqueue(encoder.encode(bufferStr));
controller.close();
return;
}
const bytes = result.value;
bufferStr += decoder.decode(bytes, {stream: true});
// this is the end of the final replacement in the FINAL string
let lastReplaceEnds = 0;
let replacedLengthDiff = 0;
bufferStr = bufferStr.replace(match, (...args) => {
const matched = args[0];
// offset is the offset in the original string, hence replacedLengthDiff
const offset = args[args.length - 2];
const replacement = replacer(...args);
replacedLengthDiff += replacement.length - matched.length;
lastReplaceEnds = offset + matched.length + replacedLengthDiff;
return replacement;
});
const newBufferStart = Math.max(bufferStr.length - bufferSize, lastReplaceEnds);
controller.enqueue(encoder.encode(bufferStr.slice(0, newBufferStart)));
bufferStr = bufferStr.slice(newBufferStart);
});
},
cancel: () => {
reader.cancel();
}
});
return new Response(stream, {
headers: response.headers
});
}