Web Push:订阅、权限与投递
一句话: Web Push 将 Push API(绑定到浏览器推送服务的 service worker 订阅)
与 Notifications API(展示消息)配对。你的服务器加密负载,POST 到订阅的 endpoint,
推送服务唤醒 service worker 的 push 事件,你再调用 self.registration.showNotification()。
在 iOS/Safari 上,这仅对用户已安装到主屏幕的 PWA 生效。
- 订阅。 在 service worker 注册激活后,调用
registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey }), 传入你的 VAPID 公钥。浏览器返回包含endpointURL 以及p256dh、auth密钥的PushSubscription。 - 存储。 将订阅 JSON 发送到服务器,按用户/设备持久化。
- 发送。 服务器加密负载(RFC 8291)、签发 VAPID JWT(RFC 8292),并 POST 到订阅的
endpoint——由浏览器厂商运营的推送服务。 - 接收。 推送服务投递到设备,设备唤醒 service worker 并触发
push事件,即使没有页面打开。 - 展示。 在
push处理器中调用showNotification();点击会触发notificationclick, 你在其中聚焦或打开正确的窗口。
Notification.requestPermission()(或 subscribe() 期间的隐式提示)必须由用户手势触发
——点击或轻触,而非页面加载时。应在有上下文时询问:在用户做出能说明通知价值的操作之后。
权限有三种状态:
default—— 尚未决定;你可以礼貌地提示一次。granted—— 你可以订阅并展示通知。denied—— 实际上不可逆;你无法再次提示,所以切勿反复请求。
由于 userVisibleOnly: true 是必需的,你发送的每条推送都必须呈现可见通知——不允许静默后台推送。
在 service worker 中处理推送与点击
Section titled “在 service worker 中处理推送与点击”self.addEventListener('push', (event) => { const data = event.data?.json() ?? {}; event.waitUntil( self.registration.showNotification(data.title ?? '更新', { body: data.body, icon: '/icons/icon-192.png', data: { url: data.url ?? '/' }, }) );});
self.addEventListener('notificationclick', (event) => { event.notification.close(); event.waitUntil(clients.openWindow(event.notification.data.url));});用 event.waitUntil() 包裹异步工作,让 service worker 在通知展示或点击处理完成前保持存活。
浏览器与生态支持
Section titled “浏览器与生态支持”| Browser / Platform | Support | Since | Confidence | Source | Notes |
|---|---|---|---|---|---|
| Chrome (Android) | ✅ yes | 50 | high | ref | — |
| Chrome (Desktop) | ✅ yes | 50 | high | ref | — |
| Edge (Desktop) | ✅ yes | 17 | high | ref | — |
| Safari (iOS) | ⚠️ partial | 16.4 | medium | ref | Only for home-screen-installed web apps; requires user-gesture permission and Web Push via APNs. |
| Safari (macOS) | ✅ yes | 16 | medium | ref | — |
| Firefox (Desktop) | ✅ yes | 44 | high | ref | — |
| Samsung Internet | ✅ yes | 5.0 | high | ref | — |
Ecosystem & commercial policy
| Entity | Type | Context | Status | Sponsored | Notes |
|---|---|---|---|---|---|
| Apple Push (APNs) | delivery_policy | iOS | ⚠️ partial | No | iOS Web Push requires the user to add the app to the Home Screen first. |
决策判定框架
Section titled “决策判定框架”| 决策问题 | 建议行为 | 理由 |
|---|---|---|
| 何时请求权限? | 在能提供上下文的用户手势之后。 | 浏览器忽略非手势触发的提示;冷提示会被拒绝。 |
| 用什么凭据来发送? | VAPID(应用服务器密钥)。 | 向推送服务标识你的服务器;无需按厂商注册账户。 |
| 需要加密负载吗? | 任何负载都需要(RFC 8291)。 | 推送服务只转发密文;浏览器用 p256dh/auth 解密。 |
| 需要触达 iOS 用户? | 先要求安装到主屏幕。 | iOS/Safari 仅向已安装的 PWA 投递 web push。 |
| 发送返回 404/410? | 删除该订阅。 | endpoint 已失效或过期;停止向其发送。 |
- 注册 service worker,并在订阅前确认其已
active。 - 从真实用户手势、有上下文地请求权限——切勿在加载时。
- 使用
userVisibleOnly: true与你的 VAPIDapplicationServerKey订阅。 - 在服务器端持久化完整的
PushSubscription(endpoint +p256dh+auth)。 - 发送时加密负载(RFC 8291)并签发 VAPID JWT(RFC 8292)。
- 始终在
push处理器中调用showNotification()(userVisibleOnly要求)。 - 处理
notificationclick:聚焦已有客户端或打开目标 URL。 - 在推送服务返回
404/410时清理订阅。 - 对 iOS/Safari,将提示限定在已安装(主屏幕)的 PWA 之后。