ServiceWorker 如何通过向所有订阅者推送来触发刷新/重新加载?

Posted

技术标签:

【中文标题】ServiceWorker 如何通过向所有订阅者推送来触发刷新/重新加载?【英文标题】:How a ServiceWorker can trigger a refresh/reload by a push to all subscribers? 【发布时间】:2021-11-04 14:03:21 【问题描述】:

这是我想要开发的过程:

带有 serviceWorker 的页面 UserA 和 UserB 仅接受来自该页面的通知

行为:

如果用户修改页面,则会通知其他用户(移动/桌面已经可以使用)

现在我想如果 userA 修改页面:

如果页面已经在 UserB 浏览器上打开,它会自动刷新 如果用户B点击通知:页面刷新

但似乎:

ServiceWorker 无法调用“重新加载” 像 setInterval 这样检查上次更新的技巧在 android chrome 上不起作用(肯定是为了带宽?)

所以我的问题是:

是否有一种方法可以让服务器推送 serviceWorker 事件以调用每个订阅者的重新加载,即使页面已经在他们的浏览器上打开?

换句话说:在页面更新时,serviceWorker 命令订阅者重新加载

这样的 serviceworker 代码失败:

   if (client.url == self.registration.scope && 'focus' in client) 
                client.postMessage('reload'); // DOESN'T WORK
                return client.focus();
            

android/chrome 上的 setinterval 失败代码:

    setInterval(async function()
    const response = await fetch('/lastupdatetimestamp', 
        method: 'get',
        headers:  'Content-Type': 'application/json' 
    );
    const json= await response.json();
    if(LASTUP<json.up.lastdate)
        window.location.reload()
        LASTUP=json.up.lastdate
    

, 30000);

有什么想法吗?

【问题讨论】:

【参考方案1】:

我终于踏出了第一步:

服务器发送推送 -> serviceworker 显示通知 -> 点击通知 -> 打开窗口并重新加载

在 serviceWorker.js 中

self.addEventListener('push', function (event)  ... 

self.addEventListener('notificationclick', async function(event) 
event.notification.close();
await event.waitUntil(clients.matchAll(
    type: "window",
    includeUncontrolled: true
).then(function(clientList) 
    for (var i = 0; i < clientList.length; i++) 
        var client = clientList[i];
        if (client.url == self.registration.scope && 'focus' in client)   //
            client.postMessage('reload'); // <= TRIGGER 'RELOAD' EVENT HERE
            return client.focus();
        
    
    if (clients.openWindow) 
        return clients.openWindow(self.registration.scope);
    
));
);

在 app.js 中

function initPostMessageListener() 
console.log("event listener message")
navigator.serviceWorker.addEventListener('message', function(e) 
  var message = e.data;
  console.log("ON A UN MESSAGE")
  switch (message) 
    case 'reload':
      window.location.reload(true);
      break;
    default:
      console.warn("Message '" + message + "' not handled.");
      break;
  
);

在注册SW的app.js中调用initPostMessageListener()

所以 SW.js 处理 notificationClick 然后打开浏览器窗口(如果存在)并重新加载它

【讨论】:

以上是关于ServiceWorker 如何通过向所有订阅者推送来触发刷新/重新加载?的主要内容,如果未能解决你的问题,请参考以下文章

微信订阅号如何用渠道二维码统计地推效果?

您如何向从应用程序本身订阅主题的用户发送 Firebase 推送通知

如何在GCP发布/订阅中推送到多个端点?

如何使用 GCP 在 pubsub 模型中一次向所有订阅者发送消息

如何通过 api 向 mailchimp 订阅者添加“标签”

从通过服务工作者创建的数据库中删除过期的推送订阅端点