服务工作者是否可以代理 iframe 子资源?

Is it possible to proxy iframe sub-resources with service workers?

我有一个依赖第 3 方资源的 iframe。 iframe 本身没有 src,不是沙盒,通过 AJAX 填充内容,其子资源(e.x。CSS,图像)存在于 CDN 上不同的域。

在我们或我们的客户发生中断的情况下,我希望能够将 iframe 的 CSS 切换到我们域中的本地文件。我正在尝试通过 Service Worker 中的 fetch 事件来做到这一点:

self.addEventListener('fetch', event => {
  const processEpubRequests = () => fetch(`/epubs/${event.request.url.split('epub-resource/')[1]}`);

  if(event.request.url.startsWith(`https://our_api.com`))
    event.respondWith(
      fetch(event.request)
        .then(response => response.status >= 400 ? processEpubRequests(response) : response)
        .catch(processEpubRequests)
    );
  else
    event.respondWith(
      caches.match(event.request)
        .then(response => response || fetch(event.request))
    );
});

这对于 AJAX 内容请求非常有用,但 CSS 似乎不起作用。它以正确的响应显示在“网络”选项卡中,但 iframe 似乎只是忽略了它。

是否可以这样处理iframe子资源?

谢谢!

编辑: 我制作了一个 Github 页演示来说明我所看到的。 页数:https://soluml.github.io/ServiceWorkerIframeExample/ 来源:https://github.com/soluml/ServiceWorkerIframeExample/tree/gh-pages

原来有一个Chrome bug out there for this issue. There are also several related issues for Firefox

但是,我们可以通过以下方式解决此问题:

  1. 将 iframe 标记设置为同源虚拟 src。

<iframe src=".iframe"></iframe>

  1. 在我们的 service worker 中响应虚拟 src(如果我们使用一个而不是实际的空白 html 文件)

if(event.request.url == `${self.location.origin}/.iframe`)
  event.respondWith(
    new Response(`<!doctype html><title>i</title>`, {
      status: 200,
      headers: { "Content-Type": "text/html" }
    })
  );

  1. 不使用 contentDocument.write(),而是使用 doc.documentElement.innerHTML。这将不会更改 iframe 中现有的 <html> 标记和 DOCTYPE。