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 没有收到消息的主要内容,如果未能解决你的问题,请参考以下文章