You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决service worker调用navigate报非客户端活跃worker错误

错误成因

  • WindowClient.navigate() 方法受安全限制,仅允许当前控制对应页面的活跃Service Worker调用,非控制方调用会直接抛出你遇到的报错
  • 你在clients.matchAll中开启了includeUncontrolled: true,会匹配到不受当前SW控制的同域页面;同时clients.claim()的Promise.resolve仅代表SW提交了控制权申请,不保证所有后台页面已经完成受控切换,2b场景下后台页面未完成受控时调用navigate()就会触发错误
  • 前台场景下页面处于活跃状态,SW控制权切换速度快,所以不会触发该问题

解决方案

推荐改用postMessage通知页面自行跳转的方案,完全规避SW控制权限制,兼容性更好,适配Quasar PWA的路由逻辑:

第一步:修改Service Worker中的通知点击逻辑

把client.navigate的逻辑替换为发消息给页面:

self.addEventListener('notificationclick', function(event) {
    console.log('notificationclick', event);
    event.notification.close();

    let route = event.notification.data.route ? JSON.parse(event.notification.data.route) : null;
    if(route && route.params && route.params.token) {
      const domain = route.domain;
      const path = '/#/' + route.name + '/' + route.params.token;
      const fullUrl = domain + path

      event.waitUntil(clients.claim().then(() => {
          return clients.matchAll({
            type: 'window',
            includeUncontrolled: true
          })
          .then(clients => clients.filter(client => client.url.indexOf(domain) !== -1))
            .then(matchingClients => {
              if (matchingClients[0]) {
                return matchingClients[0].focus().then(function (client) {
                  // 替换navigate为发消息,通知页面跳转
                  try {
                    client.postMessage({
                      type: 'NOTIFICATION_CLICK',
                      path: path
                    })
                  } catch (e) {
                    // 发消息失败兜底,直接打开新窗口
                    clients.openWindow(fullUrl);
                  }
                }).catch(function (e) {
                  console.log(e);
                });
              }
              return clients.openWindow(fullUrl);
            })
          })
      );
    }
  });

第二步:在Quasar PWA的全局逻辑中监听消息跳转

在Quasar的App.vue或者全局初始化逻辑中添加监听:

// 监听来自Service Worker的消息
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.addEventListener('message', event => {
    if (event.data.type === 'NOTIFICATION_CLICK') {
      // 调用Quasar的路由实例跳转到指定路径
      this.$router.push(event.data.path)
      // 如果你用的是Composition API,替换为对应的路由实例调用即可
    }
  })
}

可选方案:坚持使用navigate的修复方式

如果一定要用navigate方法,需要先校验SW是否拥有页面控制权:

return matchingClients[0].focus().then(async function (client) {
  // 等待SW获得页面控制权,最多等1秒
  for (let i = 0; i < 10; i++) {
    const updatedClient = await clients.get(client.id);
    if (updatedClient?.controller === self) {
      try {
        await updatedClient.navigate(fullUrl);
      } catch (e) {
        console.log(e);
        clients.openWindow(fullUrl);
      }
      return;
    }
    await new Promise(resolve => setTimeout(resolve, 100));
  }
  // 超时兜底
  clients.openWindow(fullUrl);
})

内容的提问来源于stack exchange,提问作者nulele

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 11:33:01