使用 ServiceWorker 拦截和重定向请求

问题描述

我被要求创建一个 Service Worker,它能够拦截请求并将它们重定向到存储的模拟数据。我以前从未做过这样的事情,所以我有点挣扎。当 testMode=true 添加到 URL 时,服务工作者被激活。我有 2 个文件需要处理。这是我目前所拥有的:

TestMode.ts

class TestMode {
    constructor() {
        if (!this.isEnabled()) {
            return;
        }

        if (!('serviceWorker' in navigator)) {
            console.log('browser does not support service workers');
            return;
        }

        this.init();
    }

    private init(): void {
        navigator.serviceWorker
            .register('planner-worker/js/worker.min.js')
            .then(this.handleRegistration)
            .catch((error) => { throw new Error('Service Worker registration Failed: ' + error.message); });

        navigator.serviceWorker.addEventListener('message',event => {
            // event is a MessageEvent object
            console.log(`The service worker sent me a message: ${event.data}`);
        });

        navigator.serviceWorker.ready.then( registration => {
            if (!registration.active) {
                console.log('Failed to communicate')

                return;
            }

            registration.active.postMessage("Hi service worker");
        });
    }

    private handleRegistration(registration: ServiceWorkerRegistration): void {
        registration.update();

        console.log('Registration successful,scope is:',registration.scope);
    }

    private isEnabled(): boolean {
        return locationService.hasParam('testMode');
    }
}

export default new TestMode();

serviceWorker.ts

const CACHE_NAME = 'mockData-cache';

const MOCK_DATA: Record<string,string> = {
    '/units/all?availability=Active&roomTypeHandle=kitchens': 'mock-data/unitData.json','/frontal-ranges/kitchens?' : 'mock-data/kitchensData.json','/carcase-ranges/?availability=Active&roomTypeHandle=kitchens' : 'mock-data/carcaseRangesData.json'
};


self.addEventListener('install',event => {
    console.log('Attempting to install service worker and cache static assets');
    event.waitUntil(
        caches.open(CACHE_NAME)
            .then(cache => {
                return cache.addAll(Object.values(MOCK_DATA));
            })
    );
});


self.addEventListener('activate',function(event) {
    console.log('Claiming control');
    return self.clients.claim();
});
self.addEventListener( "fetch",event => {
    console.log('WORKER: Fetching',event.request);
});

到目前为止我所做的工作,服务工作者已注册,模拟数据 json 文件存储在缓存中。

我不确定该怎么做的是,当发出某个请求时,Service Worker 将使用存储在缓存中的模拟数据。

例如,我怎样才能获得它,以便在发出以下请求时:/units/all?availability=Active&roomTypeHandle=kitchens 服务工作者将重定向到缓存中的 mock-data/unitData.json?>

我希望我说得有道理,任何帮助都将不胜感激,这对我来说是全新的。

解决方法

处理传入请求和生成响应(来自缓存、网络或两者的某种组合)的逻辑需要在您的 fetch event handler 中实现。

根据您的缓存内容和用例,我将如何构建您的 fetch 处理程序:

self.addEventListener('fetch',(event) => {
  // Using a URL object will make routing easier.
  const url = new URL(event.request.url);
  const pathAndQuery = url.pathname + url.search;

  if (pathAndQuery in MOCK_DATA) {
    const cacheKey = MOCK_DATA[pathAndQuery];
    event.respondWith(
      caches.match(cacheKey,{
        cacheName: CACHE_NAME,})
    );
  }

  // If pathAndQuery isn't in MOCK_DATA,then respondWith()
  // won't be called,and the default network behavior will
  // be used for this request.
});

您或许可以使用 https://mswjs.io/ 之类的库来替代手工编写,但如果您决定自己动手,那是总体思路。