【问题标题】:Can I edit cached index.html before serving in service worker?在服务工作者中服务之前,我可以编辑缓存的 index.html 吗?
【发布时间】:2019-08-13 06:54:12
【问题描述】:

我正在开发的 webapp 是通过 post 在 webview 中打开的。帖子正文参数(上下文用户输入)被插入到 index.html 中。

所以重复加载失败是因为上下文输入不存在。

官方文档说对此无能为力。它说您现在所能做的就是先上网并启用导航预加载。 (https://developers.google.com/web/tools/workbox/modules/workbox-navigation-preload --------- “此功能旨在为无法预缓存 HTML 的开发人员减少导航延迟......”)

因此,我正在寻找一种在使用之前编辑缓存的 index.html 的方法。我想将帖子正文参数插入到 index.html 中。我找不到任何有关编辑缓存的文档。因此,我们将不胜感激来自社区的任何帮助/意见。

【问题讨论】:

    标签: service-worker progressive-web-apps workbox


    【解决方案1】:

    工作箱!== 服务人员。 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

    【讨论】:

    • 很好的答案,我想玩这个!注意:不幸的是,在我的情况下,演示似乎被破坏了,因为 Firefox 似乎不支持TransformStream(还),而 Chromium 和最近的 Safari >= 14.1 支持。正如链接的演示页面中所包含的,我现在将测试对流的支持,如果没有这样的支持,我会回退到其他方法。
    猜你喜欢
    • 2016-05-18
    • 1970-01-01
    • 1970-01-01
    • 2023-03-31
    • 2019-07-04
    • 1970-01-01
    • 2022-08-19
    • 1970-01-01
    • 2016-10-15
    相关资源
    最近更新 更多