将服务工作者设置为仅排除特定的URL。

44

我使用 create react 构建了一个应用程序,它默认包含一个服务工作线程。我希望只要有人输入给定的 URL,应用程序就能运行,除非他们访问 /blog/,该路径提供一组静态内容。我在应用程序中使用 react router 捕捉不同的 URL。

我已经设置了 nginx 来提供 /blog/,如果有人在没有先访问 react 应用程序的情况下访问 /blog/,它可以正常工作。然而,由于服务工作线程的范围是“./”,所以只要有人访问除 /blog/ 之外的任何 URL,应用程序就会加载服务工作线程。从那时起,服务工作线程会绕过与服务器的连接,/blog/ 将加载 react 应用程序而不是静态内容。

是否有办法使服务工作线程在除了 /blog/ 之外的所有 URL 上加载?


1
你能否在你的service worker中的fetch事件监听器内发布相关代码? - Schrodinger's cat
在 Github 评论中有几种不同的解决方案。基本上,您需要编辑 sw-precache 配置中的 navigateFallbackWhitelist 字段。解决方案1解决方案2(使用 react-app-rewired) - apaatsio
9个回答

39

考虑到您还没有发布与服务工作者相关的任何代码,您可以考虑在fetch的代码块中添加一个简单的if条件语句。

这个代码块应该已经存在于您的服务工作者中。只需添加条件语句即可。

self.addEventListener( 'fetch', function ( event ) {

    if ( event.request.url.match( '^.*(\/blog\/).*$' ) ) {
        return false;
    }
     // OR

    if ( event.request.url.indexOf( '/blog/' ) !== -1 ) {
        return false;
    }
    //    **** rest of your service worker code ****

注意,您可以使用正则表达式或原型方法indexOf,具体根据您的意愿而定。

上述内容将指示您的服务工作线程仅在URL匹配/blog/时不执行任何操作。


1
@Woppi 请查看我们的 Github 仓库:https://github.com/bbhlondon/cra-append-sw。它可以让您附加 sw 功能。 - creimers
3
你知道这个新的服务工作者实现方式是如何工作的吗?它不再使用 addEventListener('fetch', ...) - F Lekschas
2
有人能更具体地说明这个变化应该在哪里吗?你所说的“your service worker”是什么?你是指registerServiceWorker.js吗?然而,我没有看到self.addEventLister(...)。 - newman
1
我还没有机会查看最新的软件实现。如果有任何更改,你能列出实现的生命周期吗? - Schrodinger's cat
1
现在的文件是 service-worker.js,可以在使用 cra 运行构建命令后生成的 build 文件夹中找到。 - Tope
显示剩余3条评论

14

使用Workbox时,另一种将URL加入黑名单(即从缓存中排除它们)的方法是使用workbox.routing.registerNavigationRoute

workbox.routing.registerNavigationRoute("/index.html", {
  blacklist: [/^\/api/,/^\/admin/],
});

上面的示例演示了这一点,针对一个单页应用程序(SPA),其中所有路由都被缓存并映射到index.html,除了任何以/api/admin开头的URL。


我为create-react-app做了这个:https://stackoverflow.com/questions/49776235/how-do-i-exclude-urls-from-service-worker-scope-in-create-react-app-without-ha/63344095#63344095 - Wayne Bloss

7

以下是我们在最新的 CRA 版本中使用的有效方法:

// serviceWorker.js

window.addEventListener('load', () => {
  if (isAdminRoute()) {
    console.info('unregistering service worker for admin route')
    unregister()
    console.info('reloading')
    window.location.reload()
    return false
  }

我们将所有位于/admin路径下的路由排除在服务器工作线程之外,因为我们在管理员区域使用了不同的应用程序。您可以根据需要更改它,以下是文件底部的函数:
function isAdminRoute() {
  return window.location.pathname.startsWith('/admin')
}

谢谢,它很棒。我进行了修改,这样我就可以动态添加更多的URL了。function isNotPwa() { const blacklist = ['store'].filter( r => window.location.pathname.startsWith(/${r})) return blacklist.length > 0 } - Doyin Olarewaju
4
这样做会取消注册所有路由的 SW,包括非管理员路由吗?如果你同时浏览这两个区域会发生什么?我想有时候你可能已经注册了 SW,有时候却没有。 - Dejan
1
正如@Dejan所说,这更像是一种自我毁灭的行为,而不是任何形式的帮助。它在页面加载时注册/注销整个SW。这不会解决OP的问题,他们想要在两种类型的页面之间移动,而不强制整个页面重新加载。 - Zane Claes

3

以下是2021年的操作步骤:

import {NavigationRoute, registerRoute} from 'workbox-routing';

const navigationRoute = new NavigationRoute(handler, {
  allowlist: [
    new RegExp('/blog/'),
  ],
  denylist: [
    new RegExp('/blog/restricted/'),
  ],
});
registerRoute(navigationRoute);

如何注册导航路由


链接已失效... - RedShift

1
如果您正在使用或愿意使用customize-cra,那么解决方案就非常简单。请将以下内容放入您的config-overrides.js文件中:
const { adjustWorkbox, override } = require("customize-cra");

module.exports = override(
  adjustWorkbox(wb => 
    Object.assign(wb, {
      navigateFallbackWhitelist: [
        ...(wb.navigateFallbackWhitelist || []),
        /^\/blog(\/.*)?/,
      ],
     })
   )
);

请注意,在最新的workbox文档中,该选项被称为navigateFallbackAllowlist,而不是navigateFallbackWhitelist。因此,根据您使用的CRA/workbox版本,您可能需要更改选项名称。
正则表达式/^/blog(/.*)?/匹配/blog、/blog/、/blog/abc123等。

0

更新(新的工作解决方案) 在最新的Create React App(版本4.x.x)中,您可以轻松地实现自定义worker-service.js而不会出现问题。自定义worker-service

从Create React App 4开始,您完全控制自定义服务工作者中的逻辑,方法是创建自己的src/service-worker.js文件或自定义cra-template-pwa(或cra-template-pwa-typescript)模板添加的文件。您可以使用Workbox项目中的其他模块,添加推送通知库或删除一些默认缓存逻辑。

如果您目前使用较旧的版本,则必须将React脚本升级到版本4。


0

CRA v4的工作解决方案

将以下代码添加到registerRoute方法中的匿名函数内的service-worker.js文件中。

// If this is a backend URL, skip
if (url.pathname.startsWith("/backend")) {
    return false;
}

0
为了简化事情,我们可以添加一个要排除的项目的数组列表,并在获取事件侦听器中添加搜索。
下面是包括和排除方法,以保证完整性。
var offlineInclude = [
    '',                // index.html
    'sitecss.css',
    'js/sitejs.js'
];

var offlineExclude = [
    '/networkimages/bigimg.png',   //exclude a file
    '/networkimages/smallimg.png',
    '/admin/'                      //exclude a directory
];

self.addEventListener("install", function(event) {
  console.log('WORKER: install event in progress.');
  event.waitUntil(
    caches
      .open(version + 'fundamentals')
      .then(function(cache) {
        return cache.addAll(offlineInclude);
      })
      .then(function() {
        console.log('WORKER: install completed');
      })
  );
});

self.addEventListener("fetch", function(event) {
  console.log('WORKER: fetch event in progress.');

  if (event.request.method !== 'GET') {
    console.log('WORKER: fetch event ignored.', event.request.method, event.request.url);
    return;
  }

  for (let i = 0; i < offlineExclude.length; i++)
  {
    if (event.request.url.indexOf(offlineExclude[i]) !== -1)
    {
      console.log('WORKER: fetch event ignored. URL in exclude list.', event.request.url);
      return false;
    }
  }

0

尝试使用 sw-precache 覆盖正在运行缓存策略的当前service-worker.js文件。 最重要的部分是设置配置文件(我将在下面粘贴我在create-react-app中使用的那个)。

  1. 安装yarn sw-precache
  2. 创建并指定配置文件,该文件指示不缓存哪些URL
  3. 修改构建脚本命令,以确保sw-precache运行并覆盖构建输出目录中的默认service-worker.js文件

我将我的配置文件命名为sw-precache-config.js,并在package.json中的构建脚本命令中指定了它。 文件内容如下。 特别要注意的部分是runtimeCaching键/选项。 "build": "NODE_ENV=development react-scripts build && sw-precache --config=sw-precache-config.js"

配置文件:sw-precache-config.js

module.exports = {
    staticFileGlobs: [
        'build/*.html',
        'build/manifest.json',
        'build/static/**/!(*map*)',
    ],
    staticFileGlobsIgnorePatterns: [/\.map$/, /asset-manifest\.json$/],
    swFilePath: './build/service-worker.js',
    stripPrefix: 'build/',
    runtimeCaching: [
        {
            urlPattern: /dont_cache_me1/,
            handler: 'networkOnly'
        }, {
            urlPattern: /dont_cache_me2/,
            handler: 'networkOnly'
        }
    ]
}

2
sw-precache已被弃用。 - Paul Melero

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接