Service Worker 没有收到消息

Posted

技术标签:

【中文标题】Service Worker 没有收到消息【英文标题】:Service Worker not receiving message 【发布时间】:2019-07-25 02:35:10 【问题描述】:

注意:使用 Create-React-App 模板...(修改其中的 Service Worker)

我正在使用通信通道 api 向服务人员发送消息以进行缓存。我使用 xmlhttp 请求是因为它的进度 api,因为 fetch 需要一个不确定的加载程序 afaik。

所以在收到 readystate 4 和状态码 200 的数据后,我将 postMessage 发送到 SW。我在客户端登录,但在服务人员中没有收到消息。

我正在本地开发并使用 Chrome 扩展程序来允许对 SW 和 Build 进行本地测试: https://chrome.google.com/webstore/detail/web-server-for-chrome/ofhbbkphhbklhfoeikjpcbhemlocgigb?hl=en

客户片段

xhr.onreadystatechange = function()
    if (this.readyState == 4 && this.status == 200) 
        const res = JSON.parse(this.responseText);

        function sendMessage(msg)
            console.log("SEND SW MESSAGE");
            const msgChan = new MessageChannel();
            // This wraps the message posting/response in a promise, which will resolve if the response doesn't
            // contain an error, and reject with the error if it does. If you'd prefer, it's possible to call
            // controller.postMessage() and set up the onmessage handler independently of a promise, but this is
            // a convenient wrapper.
            return new Promise(function(resolve, reject)
                console.log("Promise Scope");

                msgChan.port1.onmessage = function(event)
                    event.data.error ? reject(event.data.error) : resolve(event.data);
                
                // This sends the message data as well as transferring messageChannel.port2 to the service worker.
                // The service worker can then use the transferred port to reply via postMessage(), which
                // will in turn trigger the onmessage handler on messageChannel.port1.
                // See https://html.spec.whatwg.org/multipage/workers.html#dom-worker-postmessage
                navigator.serviceWorker.controller.postMessage(msg, [msgChan.port2]);
            );
        

        sendMessage(res).then(function()
            console.log("SW MESSAGE SENT");
            // Storing Quake Data
            that.props.setQuakes(res[0]);
            // Storing Three Data Obj - s-s-r Parsing and Creation
            that.props.setThreeData(res[1]);   
            // Greenlight 
            that.props.setVizInitSuccess(true);
        ).catch(function(err)
            console.log("Error Caching Data: "+err);
        );
     ;

服务工作者片段

function registerValidSW(swUrl, config) 
  navigator.serviceWorker
    .register(swUrl)
    .then(registration => 
      // Set up a listener for messages posted from the service worker.
      // The service worker is set to post a message to all its clients once it's run its activation
      // handler and taken control of the page, so you should see this message event fire once.
      // You can force it to fire again by visiting this page in an Incognito window.
      navigator.serviceWorker.onmessage = function(event) 
        console.log("SERVICE WORKER RECIEVED MESSAGE");
        console.log(event);

        event.ports[0].postMessage("SW Says Hello Back!");
        if (event.data.requireData == true && 'caches' in window) 
          // Check for cache'd data and load
          // clients.matchAll().then(clients => 
          //     clients.forEach(client => 
          //         console.log(client);
          //         //send_message_to_client(client, msg).then(m => console.log("SW Received Message: "+m));
          //     )
          // )

          // caches.open('threeData').then(function(cache)
          //   console.log("SW Cache");
          //   console.log(cache)
          //   event.ports[0].postMessage(cache);  
          // );

         else 
          // Cache Data
          caches.open('threeData').then(function(cache)
            cache.put('/data.json', new Response(event.data.json))
          );
        
      ;
...

【问题讨论】:

试试craig-russell.co.uk/2016/01/29/service-worker-messaging.html中提到的self.addEventListener方法 【参考方案1】:

Service Worker 文件中使用的navigatorWorkerNavigator 接口,而不是Navigator 接口。

WorkerNavigatorNavigator 接口的子集,允许从 Worker(在本例中为 Service Worker)访问。 WorkerNavigator Reference.

所以 Service Worker 文件中的 navigator 不包含 serviceWorker 对象。所以当你调用navigator.serviceWorker.onMessage时它会抛出错误。

要接收来自客户端的消息,请使用 Service Worker 文件中的self.addEventListener

self.addEventListener('message', event => 
  console.log(`[Message] event: `, event.data);
);

【讨论】:

所以我使用的 Create React App 模板比较有趣。如果我编辑该服务工作人员文件并使用 self ,则会出错说不能使用该变量名,例如受保护的全局变量或其他名称。但是,如果我从头开始创建一个新文件和一个工作人员,那么我就可以使用它。 其实create-react-app中的serviceWorker.js其实并不是注册的service worker。该文件在registerValidSW 函数中注册了一个服务工作者,提供了一个swUrl。该service-worker.js 文件是使用工作箱生成的。如果您在 chrome 开发工具的应用程序选项卡中检查它们。 service-worker.js 存在,它使用 Workbox 是的,我必须创建一个不同的 service worker 来使用任何 self 范围。用自定义工作人员替换 registerValidSW 中的工作箱服务工作人员。似乎工作箱工作人员只对您的基本缓存有用,因为它很难大量定制。

以上是关于Service Worker 没有收到消息的主要内容,如果未能解决你的问题,请参考以下文章

没有任何安装,我可以将 Service Worker 用作更持久的 Web Worker 吗?

service worker 消息推送

Service Worker 的中止控制器

Service Worker基础知识整理

消息传递和 Firebase 托管中的 Firebase Service Worker 错误

Firefox 和 Safari 不在 Service Worker 请求中发送自定义 http 标头