为了账号安全,请及时绑定邮箱和手机立即绑定

如何在 iframe 加载后从缓存中读取它的*原始*源

如何在 iframe 加载后从缓存中读取它的*原始*源

DIEA 2023-07-14 16:21:52
最通用的描述方式是,我只想在客户端看到视口的某一部分后仅触发一个网络请求,然后以最有效的方式使用它并在 iframe 中显示它。给定一个 DOM 结构如下:<!DOCTYPE html><html>  <head />  <body>    ...    <iframe loading="lazy" sandbox="" src="http://www.example.com" />    <pre />    ...  </body></html>我想在标签中向客户展示上述pre内容的来源iframe。该iframe元素可以承载任意文档,它可以是文本的或二进制的,所知道的是浏览器可以显示它。iframe 的源 URL 托管在同一源上。我的目标是通过访问 Chromium“view-source:”URL 或类似的 URL 来显示人们会看到的内容。访问.contentWindow或.contentdocument属性可能是不可能的,因为它完全是沙盒的,但即使我可以,文档的也outerHTML不够,并且使用 anXMLSerializer显然会改变输出。另外,我相信浏览器可以编辑文档的某些区域,例如不必要的空格或格式。我只是尝试了以下方法:document.body.querySelector("iframe").addEventListener(    "load",    async ( { currentTarget: { src } } ) => {        const data = await fetch(            src, {                cache: "only-if-cached"            }        );        // ... use data    }, {        passive: true,        once: true    });然而,获取失败。该 URL 似乎不在浏览器的缓存中,但我不想发起新的网络请求,有没有一种有效的方法可以做到这一点?我正在考虑使用 Intersection Observer 作为一种潜在的解决方案,因为它只会导致一个网络请求,但代码相当长,而且它似乎无法正常工作(我对观察者缺乏经验)。
查看完整描述

1 回答

?
海绵宝宝撒

TA贡献1809条经验 获得超8个赞

事件侦听器和获取请求可能会发生一些潜在的情况。其他读者请注意,截至撰写本文时(2020 年 11 月),仅 Chrome/Chromium、Edge 和 Opera 支持 iframe 中的延迟加载。

这个答案针对的是还想使用延迟加载来动态加载内容的提问者。如果只关心发出单个网络请求,则可以通过 fetch 请求并src通过 Blob 或数据 URI 或通过 或使用 Service Workers 设置 iframe 来完成srcdoc(下面将对此进行探讨)。

添加事件侦听器之前可能加载的帧

您可以在声明框架后将事件侦听器添加到框架中,如果在评估脚本之前加载框架(如果已缓存,则可能会出现这种情况),这可能会产生问题。

contentWindow通常,您可以通过或属性查看您的框架是否已加载contentDocument,如果是,则在这些框架上运行初始化代码,但由于该框架是沙盒的,因此无法访问这些属性。相反,您可以做的是提前声明您的处理程序,然后在创建 iframe 时声明它:

async function loader(frame) {

    console.log(frame.src);

    // ...

}

<iframe src="frame.html" loading="lazy" sandbox="" onload="loader(this)"></iframe>

在获取请求中使用同源

根据 MDNonly-if-cached只能在mode设置为 时使用same-origin,这在您的情况下应该没问题,因为您说框架是同源的。获取请求将类似于:

await fetch(src, { mode: 'same-origin', cache: 'only-if-cached' });

结果

main.html

<!doctype html>

<html>

  <head>

    <meta charset="utf-8" />

    <style>

      .spacer {

        height: 200vh;

        background: lightgray;

        text-align: center;

      }

    </style>

    <script>

      async function loader(frame) {

        var sourceCodeElementId = frame.dataset.code;

        var sourceCodeElement = document.getElementById(sourceCodeElementId);

        var response = await fetch(frame.src, {

          mode: 'same-origin',

          cache: 'only-if-cached'

        });

        if (response.status === 504) {

          // if it didn't load via cache, just get it normally

          response = await fetch(frame.src);

        }

        var text = await response.text();

        sourceCodeElement.textContent = text;

      }

    </script>

  </head>

  <body>

    <div class="spacer">Scroll Down</div>

    <iframe src="frame.html"

        loading="lazy"

        data-code="frame-source-code"

        sandbox=""

        onload="loader(this)">

    </iframe>

    <pre id="frame-source-code"></pre>

  </body>

</html>

样本frame.html


<!doctype html>

<html>

Frame

</html>

可选/替代地使用 Service Worker

如果问题是围绕网络请求,您可以使用Service Workers,作为上述修复的替代方案或补充。让它们启动并运行需要一些工作,但它们可以让您更好地控制网络请求。缓存文件是一个常见的教程,因此如果您走这条路,您应该能够找到相当数量的资源。


查看完整回答
反对 回复 2023-07-14
  • 1 回答
  • 0 关注
  • 172 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信