Foreign Fetch Service Worker Sample

Available in Chrome 54+ | View on GitHub | Browse Samples

Background

Third-party service providers can deploy foreign fetch service workers to intercept cross-origin requests from any client. For example, a web font provider might want to register a foreign fetch service worker to implement an advanced offline-first strategy for font requests, with a common cache shared amongst all its clients.

A new Link: rel="serviceworker" response header facilitates registering these third-party service workers.

Both foreign fetch itself and the Link: rel="serviceworker" header are part of an Origin Trial starting with Chrome 54, and running through March 2017. To test out a foreign fetch service worker without requiring the third-party service to sign up for an origin trial token, you can enable chrome://flags/#enable-experimental-web-platform-features. (This is not required to test the demo on this page, which makes a request against a service that has a valid Origin Trial token.)

You can read about the new functionality in more detail in this post.

Live Output

Try disabling your network connection and then requesting a new number. The foreign fetch service worker should handle the network failure for you, and return a hardcoded value of 34.

Client JavaScript

function updateRandom() {
  fetch('https://foreign-fetch-demo.appspot.com/random')
    .then(response => response.text())
    .then(number => ChromeSamples.setStatus(`Your random number is ${number}`));
}

document.querySelector('#random').addEventListener('click', updateRandom);

updateRandom();

Server Implementation

// This is the web server implementation for the "random number API".
// It is currently deployed to https://foreign-fetch-demo.appspot.com

const express = require('express');
const app = express();

const SW_JS_FILE = 'foreign-fetch-sw.js';
const MAX_RANDOM_NUMBER = 100;

app.use((req, res, next) => {
  res.setHeader('Link', `</${SW_JS_FILE}>; rel="serviceworker"`);
  res.setHeader('Access-Control-Allow-Origin', '*');
  // To test locally against a service without an Origin Trial token, enable
  // chrome://flags/#enable-experimental-web-platform-features
  // on all of the Chrome clients used for testing.
  // The deployment at https://foreign-fetch-demo.appspot.com has a
  // token, so its foreign fetch service worker does not require the flag.
  // res.setHeader('Origin-Trial', 'your-token-here');
  return next();
});

app.get('/random', (req, res) => {
  var randomNumber = Math.round(Math.random() * MAX_RANDOM_NUMBER);
  res.send(String(randomNumber));
});

app.get(`/${SW_JS_FILE}`, (req, res) => {
  res.sendFile(SW_JS_FILE, {root: '.'});
});

if (module === require.main) {
  const server = app.listen(process.env.PORT || 8080, () => {
    const port = server.address().port;
    console.log(`Server listening on port ${port}`);
  });
}

module.exports = app;

Foreign Fetch Service Worker

// This is deployed to https://foreign-fetch-demo.appspot.com/foreign-fetch-sw.js

self.addEventListener('install', event => {
  event.registerForeignFetch({
    scopes: ['/random'], // or self.registration.scope to handle everything
    origins: ['*'] // or ['https://example.com'] to limit the remote origins
  });
});

self.addEventListener('foreignfetch', event => {
  event.respondWith(
    fetch(event.request) // Try to make a network request
      .catch(() => new Response('34')) // Offline? Your random number is 34!
      .then(response => {
        return {
          response,
          origin: event.origin // Make this a CORS response
        };
      })
  );
});