【问题标题】:Intercept external URL fetch via ServiceWorker running on localhost通过在 localhost 上运行的 ServiceWorker 拦截外部 URL 获取
【发布时间】:2021-10-06 23:17:40
【问题描述】:

我有一组在 Karma 中运行的集成测试。不幸的是,他们调用了一个外部的生产 API 端点。我不想调用集成测试,我正在探索我的选择。

我想知道服务人员是否是一个可行的解决方案。我的假设是它们不起作用,因为https://github.com/w3c/ServiceWorker/issues/1188 明确表示不支持跨域获取,并且 localhost 与生产 API 端点的来源不同。

为清楚起见,这是我正在运行的一些代码:

  try {
    const { scope, installing, waiting, active } = await navigator.serviceWorker.register('./base/htdocs/test/imageMock.sw.js');
    console.log('ServiceWorker registration successful with scope: ', scope, installing, waiting, active);


    (installing || waiting || active).addEventListener('statechange', (e) => {
      console.log('state', e.target.state);
    });
  } catch (error) {
    console.error('ServiceWorker registration failed: ', error);
  }

和服务人员

// imageMock.sw.js

if (typeof self.skipWaiting === 'function') {
  console.log('self.skipWaiting() is supported.');
  self.addEventListener('install', (e) => {
    // See https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#service-worker-global-scope-skipwaiting
    e.waitUntil(self.skipWaiting());
  });
} else {
  console.log('self.skipWaiting() is not supported.');
}

if (self.clients && (typeof self.clients.claim === 'function')) {
  console.log('self.clients.claim() is supported.');
  self.addEventListener('activate', (e) => {
    // See https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#clients-claim-method
    e.waitUntil(self.clients.claim());
  });
} else {
  console.log('self.clients.claim() is not supported.');
}

self.addEventListener('fetch', (event) => {
  console.log('fetching resource', event);
  if (/\.jpg$/.test(event.request.url)) {
    const response = new Response('<p>This is a response that comes from your service worker!</p>', {
      headers: { 'Content-Type': 'text/html' },
    });

    event.respondWith(response);
  }
});

当这段代码运行时,我会在控制台中看到

ServiceWorker registration successful with scope:  http://localhost:9876/base/htdocs/test/ null null ServiceWorker

然后对https://&lt;productionServer&gt;.com/image.php 的请求不会被提取处理程序拦截。

在这种情况下没有办法拦截是正确的吗?

【问题讨论】:

    标签: javascript karma-runner service-worker


    【解决方案1】:

    可以使用服务工作者来拦截浏览器发出的请求,作为测试套件的一部分。只要 Service Worker 控制着网页,它就可以拦截跨域请求并生成您想要的任何响应。

    (关于“foreign fetch”的issue you link to 有所不同;将其视为部署自己的服务工作者的远程生产服务器。这已被放弃。)

    Stop mocking fetch”是一篇全面的文章,介绍了如何在测试套件的上下文中使用 msw 服务工作者库。

    我不能确切地说出为什么您当前的设置不起作用,但是根据过去的经验,我可以说这样做时要记住的最重要的事情是您需要延迟进行任何设置来自客户端测试页面的请求,直到页面本身由活动的服务人员控制。否则,存在竞争条件,您可能最终会触发需要触发 fetch 处理程序的请求,但如果服务工作人员尚未控制,则不会。

    您可以使用以下逻辑等待这种情况发生:

    const controlledPromise = new Promise((resolve) => {
      // Resolve right away if this page is already controlled.
      if (navigator.serviceWorker.controller) {
        resolve();
      } else {
        navigator.serviceWorker.addEventListener('controllerchange', () => {
          resolve();
        });
      }
    });
    
    await controlledPromise;
    // At this point, the page will be controlled by a service worker.
    // You can start making requests at this point.
    

    请注意,对于此用例,await navigator.serviceWorker.ready 不会为您提供所需的行为,因为在 navigator.serviceWorker.ready promise 解析和新激活的服务工作者控制当前页面之间可能存在时间间隔.您不希望这段时间间隔导致不稳定的测试。

    【讨论】:

      猜你喜欢
      • 2022-09-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-20
      • 2011-07-15
      • 1970-01-01
      • 2017-10-07
      相关资源
      最近更新 更多