企业 Web Push

Odoo 企业版通知栈为什么不是“浏览器一弹就行”:permission、worker、VAPID 心智与 opt-out 状态机讲透

这篇从企业协同通知栈角度,结合 web service worker、浏览器通知权限与移动/消息补链,讲清 Web Push 为什么本质上是一套状态机。

企业 其他
进阶 开发者 1 分钟阅读
0 评论 0 点赞 0 收藏 10 阅读

站内已经有一篇《Web Push 为什么不是勾个浏览器权限就完事》,那篇更偏设备生命周期。这一篇故意换写法:从“通知状态机”角度重讲,把企业协同栈里真正决定通知成败的四个状态拆开看——浏览器 permission、service worker 是否正常、推送身份(很多人习惯用 VAPID 来理解这一层)以及用户最终是否进入 opt-out 状态。源码锚点主要看 addons/web/controllers/webmanifest.pyaddons/web/static/src/service_worker.jsaddons/web/static/src/views/widgets/notification_alert/notification_alert.js,再结合企业版 mail_mobile 的补链心智理解。

一、permission 不是开关,而是第一层分流

notification_alert.js 里直接判断 browser.Notification.permission === "denied"。这说明浏览器权限在链路里不是一个 UI 提示,而是系统判断“后续任何 Web Push 尝试有没有意义”的第一层闸门。

对企业通知来说,这个状态至少有三种常见结果:

  • 还没授权,理论上还能争取;
  • 已授权,后面才有 worker 与订阅层的意义;
  • 已拒绝,前端通常应进入告警或静默退化逻辑。

这就是“opt-out 状态机”的第一层:用户可能不是简单没看到,而是已经明确拒绝。

二、service worker 才是通知链路的常驻执行体

webmanifest.py 会暴露 /web/service-worker.js 一类入口,web/static/src/service_worker.js 则负责离线、消息、分享等前台页面之外的能力。无论你最终是否接了标准 Web Push,worker 都是浏览器端能否承接这类异步动作的核心。

现实里很多“怎么没通知”的问题,根本不是消息没发,而是 worker 没注册、被旧版本缓存、或作用域不对。对运维和产品来说,worker 是第二层状态:permission 有了,不代表浏览器端执行体就一定健康。

三、VAPID 心智更像“谁在代表站点发通知”

严格说,本机源码里没有完整展开一个标准 Web Push VAPID 实现细节;但企业协同落地时,大家通常用 VAPID 这个概念去理解“推送身份”这一层:浏览器为什么相信这条通知代表当前站点、订阅如何和站点身份绑定、密钥更换为何会导致旧订阅失效。

所以就算你在 Odoo 代码里看到的更多是 service worker 与通知 UI,而不是一整套 VAPID 服务端实现,这层心智仍然重要。否则团队很容易把“权限正常但通知没到”误解成纯前端问题,而忽略了订阅身份、环境切换和密钥轮换的影响。

四、opt-out 不是一个字段,而是一连串静默退出条件

这篇故意把 opt-out 说成状态机,因为真实世界里用户退出通知,不止一种方式:

  • 浏览器权限直接 deny;
  • worker 被手动卸载或失效;
  • 订阅身份因环境变更而失联;
  • 用户改用移动端接收消息,不再依赖桌面端;
  • 产品层面识别到桌面通知不可用,转向其他提醒方式。

把这些都理解成“用户不想收”虽然粗糙,但在通知系统设计上非常实用:你必须接受一部分终端会静默退出,再用别的链路补回来。

五、为什么这仍然适合放进企业版选题里

因为企业协同不是单终端世界。Odoo 企业版的 mail_mobile 就体现了另一种补链思路:浏览器推不到,不代表用户完全失联,系统还可以通过移动设备 token 与 OCN 形成第二通知通道。理解 Web Push 状态机,反而更能看懂为什么企业协同需要多条提醒链路共存。

六、实战建议

  • 先查浏览器 permission 状态,不要一上来抓消息代码;
  • 再查 worker 注册、缓存与作用域;
  • 环境切换后重点核对订阅身份是否失效;
  • 最后再评估是否需要让移动端承担补链责任。

七、结论

Web Push 真正难的,从来不是“弹不弹一个通知”,而是浏览器权限、worker 健康、推送身份与用户静默退出共同形成的一套状态机。把它当成一次性的前端交互,你就永远解释不清为什么同一条消息在不同人、不同设备上表现完全不同。

主要源码锚点:

  • addons/web/controllers/webmanifest.py
  • addons/web/static/src/service_worker.js
  • addons/web/static/src/views/widgets/notification_alert/notification_alert.js
  • enterprise/mail_mobile/models/mail_thread.py

DISCUSSION

评论区

想参与讨论?先 登录 再发表评论。
还没有评论,你可以成为第一个留言的人。