【问题标题】:How can I cache external URLs using service worker?如何使用 service worker 缓存外部 URL?
【发布时间】:2017-01-18 20:27:45
【问题描述】:

我一直在使用 Google Web Starter Kit (https://github.com/google/web-starter-kit) 并且有一点渐进式 Web 应用程序正在运行,但我坚持一件事:缓存来自外部 CDN 的静态文件。例如。我正在使用来自 https://fonts.googleapis.com/icon?family=Material+Icons 的 MDL 图标我看不到缓存请求的方法,因为服务工作者只响应我的应用程序域中的 URL。

我看到的选项: 1. 下载文件并将其放在供应商文件夹中。优点:易于设置SW缓存。缺点:文件不会随着新图标的添加而保持最新(尽管这并不重要,因为我的代码只会使用可用的图标)。

  1. 使用 NPM 存储库:https://www.npmjs.com/package/material-design-icons 并使用构建步骤从 node_modules 复制 CSS 文件。优点:将允许从 NPM 自动更新。缺点:设置稍微复杂一些。

  2. 一些奇特的代理方法可以让我使用 SW 缓存外部 URL。例如myapp.com/loadExternal?url=https://fonts.googleapis.com/icon?family=Material+Icons

我现在倾向于 2,但如果知道 3 是否可能,我会很酷。

【问题讨论】:

  • 嗨,`self.addEventListener('install', e => { e.waitUntil(caches.open('cache').then(cache => { return cache.addAll([ '/ ', '/index.html', '/styles/main.css', '/scripts/main.min.js', 'fonts.googleapis.com/css?family=Quicksand:300' ]) .then(() => self.skipWaiting()); }) ) });` 这行得通吗?

标签: javascript caching service-worker


【解决方案1】:

TLDR:尝试选项 3。以后你会感谢我的。

来自Google Docs

默认情况下,如果第三方 URL 不支持 CORS,则从该 URL 获取资源会失败。您可以在请求中添加no-CORS 选项来解决此问题,尽管这会导致“不透明”响应,这意味着您将无法判断响应是否成功。

所以

选项 1

添加no-cors标头

var CACHE_NAME = 'my-site-cache-v1';
var urlsToPrefetch = [
  '/',
  '/styles/main.css',
  '/script/main.js',
  'https://fonts.googleapis.com/icon?family=Material+Icons'
];

self.addEventListener('install', function(event) {
  // Perform install steps
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(function(cache) {
        console.log('Opened cache');
        // Magic is here. Look the  mode: 'no-cors' part.
        cache.addAll(urlsToPrefetch.map(function(urlToPrefetch) {
           return new Request(urlToPrefetch, { mode: 'no-cors' });
        })).then(function() {
          console.log('All resources have been fetched and cached.');
        });
      })
  );
});

正如 OP 所说,当资源更新时,在这种情况下很难获得最新的副本。另一个问题是,正如我所说,您不会知道响应是否成功。

选项 2

或者像 OP 说的,我们可以创建一个代理服务器:简单的东西(伪代码,未经测试,Node Express 代码)

var request = require('request');
app.get('/library', function(req,res) {
  // read the param 
  var thirdPartyUrl = req.query.thirdPartyUrl;
  request(thirdPartyUrl).pipe(res);
});

当你转到/library?thirdPartyUrl=https://fonts.googleapis.com/icon?family=Material+Icons 时,应该会给你响应并缓存它,就像我们通常缓存我们的响应一样。例如:删除 no-cors 并将 urlsToPrefetch 替换为以下值:

var urlsToPrefetch = [
      '/',
      '/library?thirdPartyUrl=https://fonts.googleapis.com/icon?family=Material+Icons',
      '/library?thirdPartyUrl=https://fonts.googleapis.com/icon?family=Roboto'
    ];

选项 3

我认为这是最好和更简单的方法。使用工作箱。我们尝试过创建带有和不带有 Workbox 的 PWA,并且使用 Workbox 很简单。

了解工作箱:https://developers.google.com/web/tools/workbox/

在初始设置后实现这样的路由:

workbox.routing.registerRoute(
  new RegExp('^https://third-party.example.com/images/'),
  new workbox.strategies.CacheFirst({
    cacheName: 'image-cache',
    plugins: [
      new workbox.cacheableResponse.Plugin({
        statuses: [0, 200],
      })
    ]
  })
);

【讨论】:

  • 似乎没有获取外部/第 3 方资源的示例,请您在示例中添加该示例吗?
【解决方案2】:

我阅读了sw-toolbox docs 并想出了如何去做。只需将其添加到我的运行时缓存中:

// cache fonts hosted on google CDN
global.toolbox.router.get(/googleapis/, global.toolbox.fastest);

【讨论】:

  • 为此,我们需要将Service Worker Toolbox 安装到我们的应用程序中。对吗?
  • 没错。值得添加。重量轻,给你很多帮手。
  • 你可能想使用 Workbox,它是 sw-toolbox 和 sw-precache 的继承者:developers.google.com/web/ilt/pwa/…
【解决方案3】:

我看不到仅将请求缓存为服务工作者的方法 响应我的应用程序域中的 URL。

这是不正确的。主动控制页面的服务工作者将有机会拦截和响应对跨域资源的网络请求;标准的fetch 事件将触发,event.request.mode 将是"cors""no-cors",具体取决于页面发出的请求的上下文。

简而言之,只要有一个 Service Worker 控制一个页面,当该页面针对同源或跨域资源发出任何网络请求时,Service Worker 将能够响应fetch事件。

【讨论】:

  • 非常感谢您的澄清。我想到了。将发布答案。
  • 杰夫,请发布一些代码来举例说明如何执行 OP 的要求!
【解决方案4】:

在服务工作者中实现缓存时遇到了同样的问题。问题是图标是如何从服务器实际获取的。

1.请求是通过主 url 发出的(来自应用程序)(以黄色突出显示)。 这是一个静态请求,我想您正在尝试缓存它。

2.获取图标的实际动态网络请求(以红色突出显示)。

要解决这个问题,您需要动态填充缓存(类似这样)-

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request)
    .then((response)=>{
      if(response){
        return response;
      }
      else{
        return fetch(event.request) // response of requests
        .then((res)=>{
          return caches.open('dynamic') //create dynamic cache
          .then((cache)=>{
            cache.put(event.request.url,res.clone());
            return res;
          })
        })
      }
    })
    .catch(()=>{})
  )
});

【讨论】:

    【解决方案5】:

    我可能错位了,但就这么简单吗?

      caches.open(version)
      .then(function(cache) {
        return cache.addAll([
          '/',
          'index.html',
          '/css/app.css',
          '/js/app.min.js',
          '/assets/images/logo_target_white.png',
          '/scripts/angular-jwt.min.js',
          '/scripts/ng-file-upload.min.js',
    
           // this guy here
          'https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css'
        ]);
      })
    

    使用此方法并在 chrome 工具中检查我的应用缓存似乎显示它正确缓存。

    【讨论】:

    • 我尝试将这样的 URL 添加到我的 service Worker 的文件中以缓存数组:https://fonts.googleapis.com/css?family=Open+Sans。当我在 DevTools 中检查我的应用程序缓存时,一个空白文件返回为 'css/',大小为 0kb。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-06
    • 1970-01-01
    • 1970-01-01
    • 2018-06-22
    相关资源
    最近更新 更多