Service Worker 可以获取并缓存跨源资产吗?

2024-01-12

我正在使用一些服务人员代码Google 的渐进式 Web 应用程序教程 https://developers.google.com/web/fundamentals/codelabs/your-first-pwapp/但我收到错误:



Uncaught (in promise) TypeError:
 Failed to execute 'clone' on 'Response':
 Response body is already used
  

该网站使用第三方 Javascript 和网页字体样式表。 我想将这些 CDN 上托管的资产添加到离线缓存中。

addEventListener("fetch", function(e) {
  e.respondWith(
    caches.match(e.request).then(function(response) {
        return response || fetch(e.request).then(function(response) {
        var hosts = [
          "https://fonts.googleapis.com",
          "https://maxcdn.bootstrapcdn.com",
          "https://cdnjs.cloudflare.com"
        ];
        hosts.map(function(host) {
          if (e.request.url.indexOf(host) === 0) {
            caches.open(CACHE_NAME).then(function(cache) {
              cache.put(e.request, response.clone());
            });
          }
        });
        return response;
      });
    })
  );
});

这些托管在流行的 CDN 上,所以我的预感是他们应该为 CORS 标头做正确的事情。

以下是我想要缓存的 HTML 中的资源:

<link rel="stylesheet" type="text/css"
      href="https://fonts.googleapis.com/css?family=Merriweather:900,900italic,300,300italic">
<link rel="stylesheet" type="text/css"
      href="https://fonts.googleapis.com/css?family=Lato:900,300" rel="stylesheet">
<link rel="stylesheet" type="text/css"
      href="https://maxcdn.bootstrapcdn.com/font-awesome/latest/css/font-awesome.min.css">
<script type="text/javascript" async
        src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>

根据控制台日志,Service Worker 是trying获取这些资产:



Fetch finished loading:
 GET "https://maxcdn.bootstrapcdn.com/font-awesome/latest/css/font-awesome.min.css".
 sw.js:32
Fetch finished loading:
 GET "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML".
 sw.js:32
Fetch finished loading:
 GET "https://fonts.googleapis.com/css?family=Merriweather:900,900italic,300,300italic".
 sw.js:32
Fetch finished loading:
 GET "https://fonts.googleapis.com/css?family=Lato:900,300".
 sw.js:32
Fetch finished loading:
 GET "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/config/TeX-AMS-MML_HTMLorMML.js?V=2.7.1".
 sw.js:32
Fetch finished loading:
 GET "https://maxcdn.bootstrapcdn.com/font-awesome/latest/fonts/fontawesome-webfont.woff2?v=4.7.0".
 sw.js:32
  

如果我删除clone,正如建议的那样为什么必须在 Service Worker 中克隆 fetch 请求? https://stackoverflow.com/q/45618984/73449,我会得到同样的错误:



TypeError: Response body is already used
  

如果我添加{ mode: "no-cors" }到每获取Service Worker CORS 问题 https://stackoverflow.com/q/44808368/73449,我会收到相同的错误和这些警告:



The FetchEvent for
 "https://maxcdn.bootstrapcdn.com/font-awesome/latest/fonts/fontawesome-webfont.woff2?v=4.7.0"
 resulted in a network error response: an "opaque" response was
 used for a request whose type is not no-cors
The FetchEvent for
 "https://fonts.gstatic.com/s/lato/v14/S6u9w4BMUTPHh50XSwiPGQ3q5d0.woff2"
 resulted in a network error response: an "opaque" response was
 used for a request whose type is not no-cors
The FetchEvent for
 "https://fonts.gstatic.com/s/lato/v14/S6u9w4BMUTPHh7USSwiPGQ3q5d0.woff2"
 resulted in a network error response: an "opaque" response was
 used for a request whose type is not no-cors
The FetchEvent for
 "https://fonts.gstatic.com/s/merriweather/v19/u-4n0qyriQwlOrhSvowK_l521wRZWMf6hPvhPQ.woff2"
 resulted in a network error response: an "opaque" response was
 used for a request whose type is not no-cors
  

我可以将这些资产添加到服务工作人员的静态缓存中install事件,但我有理由仅在fetch event.


你在正确的轨道上使用clone() https://developer.mozilla.org/en-US/docs/Web/API/Response/clone,但时机很重要。您需要确保您致电clone()决赛前return response执行,因为此时响应将被传递到 Service Worker 的客户端页面,并且其主体将被“消耗”。

有两种方法可以解决此问题:要么调用clone()在执行异步缓存代码之前,或者延迟您的return response语句直到缓存完成之后。

我建议使用第一种方法,因为这意味着您最终将尽快收到页面的响应。我还建议您重写代码以使用async/await https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function,因为它更具可读性(并且受到当今支持服务工作者的任何浏览器的支持)。

addEventListener("fetch", function(e) {
  e.respondWith((async function() {
    const cachedResponse = await caches.match(e.request);
    if (cachedResponse) {
      return cachedResponse;
    }

    const networkResponse = await fetch(e.request);

    const hosts = [
      'https://fonts.googleapis.com',
      'https://maxcdn.bootstrapcdn.com',
      'https://cdnjs.cloudflare.com',
    ];

    if (hosts.some((host) => e.request.url.startsWith(host))) {
      // This clone() happens before `return networkResponse` 
      const clonedResponse = networkResponse.clone();

      e.waitUntil((async function() {
        const cache = await caches.open(CACHE_NAME);
        // This will be called after `return networkResponse`
        // so make sure you already have the clone!
        await cache.put(e.request, clonedResponse);
      })());
    }

    return networkResponse;
  })());
});

注:(async function() {})()语法可能看起来有点奇怪,但它是一个使用的快捷方式async/await在一个立即执行的函数中,该函数将返回一个承诺。看http://2ality.com/2016/10/async-function-tips.html#immediately-invoked-async-function-expressions http://2ality.com/2016/10/async-function-tips.html#immediately-invoked-async-function-expressions

对于原始代码,您需要在执行异步缓存更新之前克隆响应:

        var clonedResponse = response.clone();
        caches.open(CACHE_NAME).then(function(cache) {
          cache.put(e.request, clonedResponse);
        });

The Google 的 Service Worker 入门书 https://developers.google.com/web/fundamentals/primers/service-workers/有示例代码显示正确的方法。该代码有一个带有“重要”注释的注释,但它只是强调克隆,而不是克隆时遇到的问题:

        // IMPORTANT: Clone the response. A response is a stream
        // and because we want the browser to consume the response
        // as well as the cache consuming the response, we need
        // to clone it so we have two streams.
        var responseToCache = response.clone();

        caches.open(CACHE_NAME)
          .then(function(cache) {
            cache.put(event.request, responseToCache);
          });

        return response;
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Service Worker 可以获取并缓存跨源资产吗? 的相关文章

  • Jasmine 条件 callThrough 和 callFake

    我有一个返回函数引用的方法 function methodetobeMoked param case1 return func1 case 2 return func2 case n return funcN 我需要监视这个方法并返回特定输
  • 如何使用 Shopify API 将商品添加到购物车

    我正在使用 Shopify API 开发自定义网络应用程序 这里的想法是使用应用程序作为独家店面 只需向 Shopify API 发出请求 我已在我的 Shopify 帐户中设置了一个私人应用程序来执行此操作 我从 api 提取产品没有问题
  • 少吞咽然后缩小任务

    我必须在 gulp 中执行 2 个步骤 减少 css 文件格式 缩小生成的 css 文件 这是我的吞咽文件 var gulp require gulp watch require gulp watch less require gulp l
  • Javascript hasOwnProperty 在事件对象上总是 false?

    我希望有人可以帮助澄清与事件对象相关的 hasOwnProperty 方法 我正在尝试克隆鼠标事件 最终该对象将被传递到 iframe 我已经构建了一个 克隆 函数 但每当我尝试克隆窗口事件 即滚动 单击等 时 hasOwnProperty
  • 如何使用jquery格式化数字

    我正在尝试删除 之后的数字 然后我想格式化数字 16810900 211233 喜欢这个 16 810 900 但我不知道该怎么做 这是我的 html 是这样的 div class main p class active 10200 00
  • AngularJS 忽略一些标头

    我正在玩一点 Angular 遇到了一个小问题 我正在尝试为http响应设置一个自定义标头 然后在角度方面读取它的值 标头已设置 我确信这一点 因为 chrome 的调试工具确认了 这意味着服务器端没问题 到目前为止 一切都很好 当我尝试通
  • 粉碎一个元素,向随机方向发送碎片

    我试图 粉碎 一个元素 例如 一个图像 并将其碎片朝随机方向飞行 当碎片到达目的地时 即x距离 以像素为单位 它们变成原始图像的较小版本 jQuery UI 的explode http api jqueryui com explode ef
  • 如何在Javascript中声明静态变量[重复]

    这个问题在这里已经有答案了 在下面的代码中 我希望有一个计数器来跟踪创建的 Person 对象的数量 这段代码没有这样做 我该如何实现呢 function Person this name Peter this counter this c
  • 如何更改点击事件上的引导插入符指向方向

    我正在使用 2 3 2 引导程序 因为当我单击菜单按钮时 我可以更改插入符号图标的位置 我需要当我单击图标插入符号向上时 当您单击另一个项目时 插入符号返回到初始状态 这怎么可能 导航代码 div div class container d
  • 将其作为参数传递给 addEventListener()

    我想添加change一组复选框的事件 我如何访问this在我的事件函数中 这样当我执行事件时我可以访问复选框的值 这是我当前的代码 var checkboxes document getElementsByClassName cb Arra
  • 按日期对 JSON 进行排序

    我知道这一定相对简单 但我有一个 JSON 数据集 我想按日期排序 到目前为止 我每次都会遇到问题 现在我将日期存储为this lastUpdated 如果有帮助的话 我可以访问 jquery 但我意识到 sort 是本机 JS 提前致谢
  • 使用 Javascript 对象模型在 SharePoint 任务上设置“分配给”

    我想创建一个共享点任务并将其分配给我自己 当前用户 在 javascript 对象模型中 我有下面的代码 但我认为我需要设置 spusercollection 对象 而不是设置特定用户 但是 我似乎无法在任何地方找到如何执行此操作的任何示例
  • 内联执行生成的汇编程序

    我正在阅读以下演示文稿 http wingolog org pub qc 2012 js slides pdf http wingolog org pub qc 2012 js slides pdf其中讨论了 4 10 19 内联 ASM
  • Javascript“命名空间”和 jQuery AJAX

    我正在使用此处列出的建议 http www odetocode com articles 473 aspx http www odetocode com articles 473 aspx 使用模拟的JavaScript AJAX网络聊天系
  • Backbone.js 应用程序可以逐步增强并可供搜索引擎抓取吗?

    我需要为我的下一个项目实现一个 MVC JavaScript 框架 但它既是一个网站 又是一个 Web 应用程序 是否可以公开数据服务器端 然后解析 URL 以显示 JS 版本 我计划使用 Rails 作为服务器端代码 我写了一个关于这个主
  • 元素在主体内找不到足够的空间 - JavaScript 样式

    相关信息 该页面包含两个元素 An
  • 用于图形操作的 Javascript 库

    有没有建议的 javascript 替代 pythonpygraph http code google com p python graph or NetworkX http networkx lanl gov 应该注意的是 可视化不是必需
  • 加载 angularjs 路由后运行 javascript 代码

    我需要在 angularjs 加载路线后显示警报 显示警报的代码位于 angularjs 异步加载的视图中 视图加载后 我希望它能够运行 但它没有 我知道我可以广播并告诉它稍后运行等 但我需要一个更通用的解决方案 假设您正在谈论基于以下内容
  • 正则表达式获取两个方括号之间的数字

    您好 我需要使用正则表达式在 JavaScript 中获取两对方括号内的字符串 这是我的字符串 12 23 asd 到目前为止我尝试的是使用这种模式 d 我需要获得价值12使用正则表达式 您可以使用以下正则表达式 d 这将提取12 from
  • 检测图像是否损坏或损坏

    我需要以编程方式检查用户在我的应用程序上选择作为壁纸的图像是否已损坏或损坏 基本上我为用户提供了选择自己的图像作为壁纸的选项 现在 当图像加载时 我只想检查它是否已损坏 如果您正在寻找 PHP 解决方案而不是 javascript 解决方案

随机推荐

  • 配对括号的正则表达式

    输入线是这样的 只是其中的一部分 Text Text Text text text text asdasdasdasda asdasdasdasd 我想要的是列出所有匹配项 其中文本包含在一对中 and 我确实尝试了几种模式 但是当未关闭时
  • 为什么将数据写入文件时出现此错误

    我有这个代码 myvector lt c 3 45235 1 32525 2 41351 some numbers write myvector C mypath myfile txt I use instead of 我收到以下错误 文件
  • javascript window.open 在 safari 中

    我在 safari ipad 和桌面版本 中打开一个新窗口时遇到了一个与弹出窗口阻止程序有关的问题 基本上我发现如果 window open 没有从点击事件中调用 safari 将阻止弹出窗口 调用 window open 的事件当前正在从
  • 在列表视图中添加复选框 (C#)

    我想在 C 应用程序中显示一个列表视图 其中每一行代表一个产品 因此属性 视图 设置为 详细信息 一列 最后一列 应该是一个复选框 因为它代表产品是否打折 将 checkboxes 属性设置为 true 后 第一列中会出现一个复选框 因此它
  • 如何使用php获取oracle 11g xe中最后插入记录的序列id?

    在这里 我试图插入一条记录并检索最后插入的序列ID 但没有取得任何成功 有人可以帮助我 指导我oracle如何与php一起工作吗 query INSERT INTO hist news id headline reportedon repo
  • .NET Core WebAPI 后备 API 版本,以防缺少次要版本

    经过多次尝试和阅读文章后 我决定将我的问题放在这里 我想要的是 我正在研究应用程序的 api 版本控制 NET Core 支持的版本格式 Microsoft AspNetCore Mvc Versioningpackage 是 Major
  • 将 git 子模块协议从 git 替换为 http

    我从 git URL 添加一个子模块 以便能够在其中进行开发 现在我想部署应用程序并将 URL 替换为 git 因此它不需要从 Capistrano 对子模块的存储库进行身份验证 编辑 gitmodules 中的 URL 是否足以完成此任务
  • TypeScript -> AST -> TypeScript

    有没有办法将 TypeScript 文件解析为 AST 修改 AST 然后将其解析回 TypeScript 作为工具Esprima http esprima org 埃斯科德根 https github com estools escode
  • setNeedsLayout 和 setNeedsDisplay

    两者之间真正的区别是什么UIView方法setNeedsLayout and setNeedsDisplay 像往常一样 文档对此模糊不清 其实文档对此说得很清楚 设置需求布局 http developer apple com librar
  • 确定锁升级的阈值

    我有一个包含大约 250 万条记录的表 将更新其中大约 70 万条记录 并且希望更新这些记录 同时仍允许其他用户查看数据 我的更新语句看起来像这样 UPDATE A WITH UPDLOCK ROWLOCK SET A field B fi
  • 使用 Cython 编译 Python 脚本是否会减少启动时间?

    众所周知 Python 程序启动速度有点慢 用cython编译整个程序可以解决这个问题吗 None
  • 如何在重定向中发送参数 - php codeigniter

    下面的代码给了我一个错误 我想调用一个函数并使用 php codeigniter 向其传递一个参数 redirect base url MainController Student Login user email 这里 MainContr
  • 无法在管道阶段定义变量

    我正在尝试创建一个声明性 Jenkins 管道脚本 但在简单变量声明方面遇到问题 这是我的脚本 pipeline agent none stages stage first def foo foo fails with WorkflowSc
  • 如何返回前一个索引之后的下一个索引?

    例如 str a b c d e f str indexOf 0 str lastIndexOf 12 如何获取第二个括号中的索引 c d int first str indexOf int next str indexOf first 1
  • 从 MVC / IIS Web 应用程序为包含子域提供服务

    我在 tumblr 上托管我的网站博客 博客 withoomph com 我已经修改了博客上的主题 并且想使用我在主网站上使用的自己的字体 我正在尝试从以下位置获取字体 beta withoomph com 但是 当页面尝试获取字体时 我收
  • aio_write() 和 O_NONBLOCK write() 之间的区别

    aio write 和 O NONBLOCK write 有什么区别 另外 我使用 O NONBLOCK 函数使用文件描述符对文本文件进行 write 操作 并通过在函数前后放置一个计时器来将性能与 aio write 进行比较 当字符串长
  • 使用iOS 9.0中的CNContactPickerViewController,如何启用/禁用单选或多选?

    委托 CNContactPickerDelegate 具有用于单选和多项选择的方法 但是当我们呈现视图控制器时 我们如何指定我们想要单选或多选呢 我想我错过了一些可能也会导致我所描述的问题的东西 CNUI 错误 设置了选择谓词 但委托未实现
  • Woocommerce 3 中的可编辑管理自定义计费字段错误问题

    我在此代码中遇到错误 在订单编辑页面中添加可编辑的自定义计费字段 add filter woocommerce admin billing fields order admin custom fields function order ad
  • WordPress 单个帖子内容不显示

    我有一个 WordPress 博客主题 它可以很好地显示索引上所有帖子的内容 但是当我点击其中一篇帖子时 该帖子的内容是空白的 我似乎不明白为什么 如果我是正确的single php控制该页面 http pastebin com afLVx
  • Service Worker 可以获取并缓存跨源资产吗?

    我正在使用一些服务人员代码Google 的渐进式 Web 应用程序教程 https developers google com web fundamentals codelabs your first pwapp 但我收到错误 Uncaug