How can I cache external URLs using service worker?

情到浓时终转凉″ 提交于 2021-02-16 05:50:18

问题


I've been playing with the Google Web Starter Kit (https://github.com/google/web-starter-kit) and have got a little progressive web app working but am stuck on one thing: caching static files from external CDNs. E.g. I'm using MDL icons from https://fonts.googleapis.com/icon?family=Material+Icons I can't see a way to cache the request as the service worker only responds to URLs within my app domain.

Options I see: 1. Download the file and put it in a vendor folder. Advantages: easy to set up SW cache. Disadvantages: file won't stay up to date as new icons are added (though that won't really matter as my code will only use the icons available).

  1. Use the NPM repo: https://www.npmjs.com/package/material-design-icons and use build step to copy CSS file from node_modules. Advantages: will allow auto-updating from NPM. Disadvantages: slightly more complex to set up.

  2. Some fancy proxy method that would allow me to use the SW to cache an external URL. e.g. myapp.com/loadExternal?url=https://fonts.googleapis.com/icon?family=Material+Icons

I'm leaning towards 2 right now but would be cool to know if 3 is possible.


回答1:


TLDR: Try Option 3. You'll thank me later.

From Google Docs:

By default, fetching a resource from a third party URL will fail if it doesn't support CORS. You can add a no-CORS option to the Request to overcome this, although this will cause an 'opaque' response, which means you won't be able to tell if the response was successful or not.

So

Option 1

Add no-cors header

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.');
        });
      })
  );
});

As OP said, when the resource is updated, it's hard to get the latest copy in this scenario. And another issue is, as I said you won't know whether the response was a success or not.

Option 2

Or like OP said, we can create a proxy server: Something simple as (Pseudocode, not tested, Node Express code)

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

And when you goto /library?thirdPartyUrl=https://fonts.googleapis.com/icon?family=Material+Icons should give you the response and cache it how we normally cache our response. For Ex: remove no-cors & replace urlsToPrefetch with below value:

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

Option 3

I think this is the best and easier way. Use workbox. We've tried to create PWA with and without workbox and using workbox was simple.

Read about workbox: https://developers.google.com/web/tools/workbox/

Implement a route like this after the initial setup:

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],
      })
    ]
  })
);



回答2:


I had a read of the sw-toolbox docs and figured out how to do it. Just had to add this to my runtime caching:

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



回答3:


I can't see a way to cache the request as the service worker only responds to URLs within my app domain.

That's not correct. A service worker that's actively controlling a page will have an opportunity to intercept and respond to network requests for cross-origin resources; the standard fetch event will fire, and event.request.mode will either be "cors" or "no-cors", depending on the context of the request made by the page.

In short, as long as there's a service worker in control of a page, when that page makes any network request, for either same- or cross-origin resource, the service worker will be able to respond to the fetch event.




回答4:


Faced the same issue while implementing caching in service worker.The issue is how the icons are actually fetched from the server.

1.Request is made via the main url(from the application)(Highlighted in yellow). This is a static request which you are trying to cache i suppose.

2.Actual dynamic network request made to get the icon(Highlighted in red).

To fix this, you need to dynamically populate the cache(Something like this)-

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:


I may be misaligned, but is it as simple as the following?

  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'
    ]);
  })

Using this method and inspecting my app cache in chrome tools seems to show it caching properly.



来源:https://stackoverflow.com/questions/39432717/how-can-i-cache-external-urls-using-service-worker

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!