Web 推送通知:运行原理与用好它的方法

Web 推送通知如何工作,从 Service Worker 和 VAPID 到包括 iOS 在内的真实浏览器支持情况,再到决定成败的授权体验与指标。

web push notifications

简短的回答是什么?

Web 推送通知是网站通过推送服务发给浏览器的消息,由 Service Worker 投递,即使站点已经关闭也能送达。它需要按浏览器和来源分别取得明确授权,一旦被拒绝,站点无法再次弹出提示。在 iOS 和 iPadOS 上,Web Push 只对已添加到主屏幕的 Web 应用有效。

了解更多
在本页面

Web 推送通知是唯一一个渠道:一个糟糕的设计决定,就可能把你永久挡在客户之外。在错误的时机请求授权,访客点了“屏蔽”,那个浏览器就对你永远关闭了。没有二次提示,没有第二次营销活动,也没有挽回邮件。正是这种不对称,让人在写下第一条消息之前就值得先弄懂它的机制。

Web 推送通知是什么

Web 推送通知是从你的服务器发到订阅者浏览器的一条消息,由操作系统的通知中心展示,即使你的站点已经关闭也能送达。最后这一点才是关键:与页面内弹窗不同,Web 推送能触达此刻并没有在看你网站的人。

它由三个协同工作的 Web 平台 API 构成,而它们之间的分工解释了这个渠道的大部分行为:Service Worker API、Push API 和 Notifications API。

Web 推送的底层运行方式

Service Worker

Service Worker 是一个 JavaScript worker,充当 Web 应用、浏览器与网络之间的代理。它运行在独立线程上,没有 DOM 访问权限,并且在注册它的页面关闭之后继续存在。正是这种持久性,让它能在你的标签页都没打开时接收推送消息并展示通知。Service Worker 只能在安全上下文中运行,也就是 HTTPS,开发时 http://localhost 被视为安全。

订阅:一个 endpoint 加两把密钥

Service Worker 激活之后,页面调用 registration.pushManager.subscribe()。浏览器与厂商的推送服务通信,返回一个 PushSubscription,其中包含:

  • endpoint,推送服务接收消息的唯一能力 URL
  • keys.p256dh,P-256 曲线上的椭圆曲线 Diffie-Hellman 公钥
  • keys.auth,一个认证密钥

你的服务器要把这三项都存下来,并把 endpoint 当作机密对待,因为任何拿到它的人都能向该订阅者发送消息。密钥的存在是因为负载采用端到端加密。RFC 8291 规定了做法:P-256 上的 ECDH 交换建立共享密钥,HKDF 从中派生出密钥,负载在 aes128gcm 内容编码下用 AES-128-GCM 封装。推送服务转发的是它读不懂的密文。

推送服务

你并不是把推送消息直接发给设备。你发给的是浏览器厂商运营的推送服务:Chrome 用 Google 的 FCM endpoint,Firefox 用 Mozilla 的 autopush,Safari 用 Apple 的推送服务。RFC 8030 “Generic Event Delivery Using HTTP Push” 定义了这套协议。你的服务器向订阅 endpoint 发起 POST,推送服务负责移动端投递中最难的部分:与设备保持一条省电的连接,离线时排队,消息到达时唤醒浏览器。这也是投递无法被保证的原因。如果设备关机时间够长,消息会按各自的 TTL 过期并被丢弃。

VAPID:证明是谁在发送

仅靠 endpoint 保密,安全性很薄弱。RFC 8292 引入了 Voluntary Application Server Identification,即 VAPID,让推送服务能分辨消息来自哪台应用服务器。

你在 NIST P-256 曲线上生成一对 ECDSA 密钥,只需一次。浏览器订阅时把公钥放进 applicationServerKey,从而把订阅与你的服务器绑定。每次推送时,你的服务器用对应私钥以 ES256 签发一个 JWT,其中带有指向推送服务来源的 aud 声明、不超过 24 小时的 exp 声明,以及可选的带联系方式的 sub 声明。推送服务会验证签名,因此仅仅偷走一个 endpoint 已不足以骚扰你的订阅者。

端到端的投递路径

  1. 页面注册 Service Worker,在授权通过后用你的 VAPID 公钥调用 subscribe()。
  2. 你的服务器把返回的 endpoint 和密钥存入订阅者记录。
  3. 发送时,服务器用 p256dh 和 auth 加密负载,签发 VAPID JWT,并向 endpoint 发起 POST。
  4. 推送服务验证请求并投递加密消息。
  5. 浏览器以 push 事件唤醒 Service Worker,由它解密负载并调用 ServiceWorkerRegistration.showNotification()。
  6. 点击会在 Service Worker 中触发 notificationclick,你在这里打开目标 URL。

授权模型为什么如此严格

看看一次订阅授予了什么:一个在你站点未打开时仍会运行的后台进程,加上在操作系统通知界面上绘制内容的能力。所以浏览器把它锁在一道明确的、按来源划分的、由用户授予的权限之后,而且多数浏览器要求请求必须跟随一次真实的用户手势。

第二条约束常让人意外。Chrome 和 Edge 要求订阅时带上 userVisibleOnly: true,这是一个承诺:每一次推送都会产生用户可见的通知,因此静默的后台推送并不是这个 API 支持的用法。Firefox 也会对不产生通知的推送消息设置配额。

浏览器与平台支持

按 MDN 的说法,Push API 自 2023 年 3 月起已是 Baseline 广泛可用,意味着它在桌面端的 Chrome、Edge、Firefox 和 Safari 当前版本上可用,在 Android 的 Chrome 和 Firefox 上也可用。有两点注意事项比这个结论本身更重要。

第一,Notifications API 并非各处一致可用。MDN 标注它为有限可用,因为 Notification() 构造函数在大多数移动浏览器上会抛出 TypeError。凡是必须在手机上工作的场景,请改用 ServiceWorkerRegistration.showNotification() 的持久化通知,反正你走的就是 Service Worker 这条路。

第二,通知选项的实现参差不齐。操作按钮、角标、图片和 requireInteraction 在不同浏览器和操作系统上表现不一,所以要把通知设计成只有标题、正文和图标时也读得通。

iOS 与 iPadOS 的前提条件

这条限制决定了 Web 推送对以移动端为主的受众是否可行,而它几乎在所有地方都被讲错了。

Apple 在 iOS 与 iPadOS 16.4 中加入了 Web Push,并且只对已添加到主屏幕的 Web 应用有效。用 WebKit 的原话说,“我们正在为主屏幕 Web 应用加入对 Web Push 的支持”,而且“已添加到主屏幕的 Web 应用可以请求接收推送通知的权限”。用户通过分享菜单里的“添加到主屏幕”完成这一步,之后授权请求必须由用户的直接操作触发,例如点击一个订阅按钮。

在 iPhone 上以普通 Safari 标签页打开的站点无法创建推送订阅。这是一道真实的门槛:你还没来得及请求授权,就先要求对方完成一次安装动作。在 macOS 上情况轻松得多,因为 macOS Ventura 上的 Safari 16.1 为普通网站带来了基于标准的 Web Push,无需任何安装步骤。

一个最小订阅示例

这就是客户端的完整流程。它应该放在点击处理函数里,而不是页面加载时。

async function subscribeToPush(vapidPublicKey) {
// 推送和 Service Worker 需要安全上下文(HTTPS)。
if (!("serviceWorker" in navigator) || !("PushManager" in window)) return null;
const registration = await navigator.serviceWorker.register("/sw.js");
// 必须由用户手势触发调用,且每位用户只调用一次。
const permission = await Notification.requestPermission();
if (permission !== "granted") return null;
const subscription = await registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: vapidPublicKey, // base64url 编码的 P-256 公钥
});
// 在服务端保存 endpoint 与密钥;把 endpoint 当作机密对待。
await fetch("/api/push/subscribe", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(subscription),
});
return subscription;
}

在 sw.js 里,你处理 push 事件,调用 self.registration.showNotification(title, options),并处理 notificationclick 以打开目标 URL。

授权体验:多数项目失败的地方

永远不要在页面加载时询问

Lighthouse 为此专门设了一项审计:“如果你的页面在加载时就请求发送通知的权限,这些通知可能与用户或其需求并不相关”。它的建议是提供一种具体类型的通知,只有在用户选择了该类型之后才请求授权。Safari 12.1 和其他浏览器走得更远,要求必须先与页面发生交互才允许发起请求。

使用软性预提示

先展示你自己的页面内邀请。它说明价值主张,可以被关闭且没有永久代价,只有点击它才会触发真正的浏览器提示。今天忽略软提示的人,下个月还能再问一次;点了“屏蔽”的人则不能。有两条规则让它奏效:说清楚你实际会发什么,而不是“获取更新”;绝不要诱导误点,因为误触带来的接受会立刻换来退订。

在恰当的场景中询问

Chrome 自己的建议是“让用户自己主动,按他们自己的节奏开启通知”,把开关低调地放进已有的界面里,并避免“在没有场景铺垫的情况下,或在用户刚落地站点时就展示提示或浮层”。

在电商中真正奏效的时刻很具体:售罄商品上的“到货通知我”控件、提供配送更新的订单确认页、常看商品上的降价提醒开关。授权是用一项被明确说出的好处换来的,而不是被顺手收割的。

一次拒绝几乎是永久的

当有人屏蔽通知时,浏览器会为你的来源保存这个决定。之后调用 Notification.requestPermission() 会直接返回已存储的 denied 值,不展示任何内容,这也是 MDN 自己的示例在调用 requestPermission() 之前先检查 Notification.permission 的原因。撤销屏蔽意味着要翻进站点设置,而基本上没人会这么做。

做错了浏览器会怎么处理

后果早已不只是订阅率低。

  • Chrome 会自动把接受率极低的来源纳入更安静的授权界面,并按设备类型分别判断,对所有人抑制提示。
  • Chrome 会对高推送量加低互动的站点施加速率限制,返回 HTTP 429。升级机制先是一天,然后七天,再十四天,只有在连续 42 天没有打扰行为后才重置。
  • Chrome 现在会自动撤销用户近期没有互动过的站点的通知权限,条件是“用户互动极低,同时发送的通知量很大”。Google 给出的理由很直白:“所有通知中,得到用户任何互动的不足 1%。”

只要发得糟糕,你就会失去已经赢得的订阅者。

Web 推送与邮件、短信的对比

维度Web 推送邮件短信
触达范围仅限已订阅的浏览器任何有邮箱地址的人任何有手机号的人
边际成本基本为零极低按条计费,最高
即时性数秒,由操作系统呈现数分钟到数天,埋在收件箱里数秒
消息长度一个标题加一行短正文不限长度,富文本排版每条约 160 个字符
同意方式浏览器提示,一次点击收集地址,最好是双重确认订阅明确同意且受严格监管
身份一台设备上的一个浏览器一个人一个人
可迁移性无完整导出完整导出

改变策略的所有权差异

一次推送订阅是绑定在某台设备某个浏览器配置上的能力 URL。它不是一个人。同一位客户在笔记本上用 Chrome、在手机上用 Firefox,就是两个互不相关的订阅,除非他们主动表明身份,否则你无从知道那是同一个人。

它也不可迁移。你可以导出邮件列表,明天就装进另一个平台。推送订阅无法在厂商之间搬迁,因为密钥和 VAPID 绑定是针对某个特定应用服务器密钥创建的。

所以把 Web 推送当作自有渠道的助推器,绝不要当作替代品。用推送这个时刻去换取一个邮箱地址或手机号,而不是反过来。营销自动化完整指南讲了如何把多个渠道接进同一条旅程。

真正有效的使用场景

这个渠道偏爱那些时效性强、与个人高度相关、一次点击即可行动的消息。

  • 弃购挽回。 一小时内推送一次,稍后再用邮件加强。弃购邮件指南讲了节奏安排。
  • 到货提醒。 最强的场景,因为用户明确要求被告知。
  • 关注商品降价。 同样的逻辑,相关性由用户自选。
  • 配送与订单状态。 打开意愿高,投诉风险低。
  • 已订阅主题下的突发更新。 新闻、赛果、可预约时段。

失败的场景同样清晰:泛泛的“我们发布了新文章”广播、千篇一律的每日优惠、任何超过一个标题加一行的内容、向已经忽略了上二十条通知的订阅者做的唤醒轰炸,以及需要留存凭据的交易类内容。

频次、时机与细分

保守起步:每位订阅者每周一到三条,只有在退订率和点击率保持稳定时才增加。疲劳出现得比邮件更快,因为静音只需要在操作系统已经推到眼前的通知上点一下。

时机既是优势也是风险。推送即时送达,所以凌晨 2 点发出的消息就在凌晨 2 点到达。在订阅时存储或推断订阅者的时区,并把发送控制在设定的时间窗内。

细分受限于你对一次订阅而非一个人的了解,因此可用的维度都是行为类的:浏览过的页面、关注的商品、购物车状态、最近购买时间、平台。客户细分指南讲得更深。

衡量 Web 推送

有四个指标重要,而且它们的可测量方式并不相同。

  • 投递。 推送服务是否接受了请求。201 表示已接受,不等于已送达。404 或 410 表示订阅已失效。
  • 展示。 通知是否被显示。只有当 showNotification() 完成后 Service Worker 回报时你才知道。
  • 点击率。 点击数除以展示数。这是值得优化的数字。
  • 退订率。 每次发送带来的退订与权限撤销。要比点击率盯得更紧,因为它是渠道走向死亡的先行指标。

归因陷阱

推送的归因容易自我美化。通知到达的是订阅者本来就握在手里的设备,所以它常常把一次本来也会发生的会话算作自己的功劳。用对照组,而不是假定增量存在。展示数被少计而每次点击都被记录,因此用发送数作分母算出的点击率会高估表现。又因为一次订阅是一个浏览器而不是一个人,在手机上点击、最终在桌面端完成购买的推送看起来像两件互不相关的事。邮件营销指标指南讲了跨渠道的衡量卫生。

同意、GDPR 与退订

浏览器的授权提示是技术闸门,它并不自动构成营销的完整合法性基础。

如果你面向欧盟或英国的人做营销,请像对待邮件一样对待推送。在提示出现之前说明你会发什么,让同意是知情且具体的。记录订阅创建的时间和位置,绝不要把推送同意捆绑进一个无关的操作。如果你把订阅与已识别的客户关联起来,那些数据就落入你的个人数据义务范围,包括删除请求。

退订卫生同样重要。提供站内偏好设置控件,让人们能降低频次而不是直接屏蔽;他们这么做时,调用 PushSubscription.unsubscribe() 并在服务端删除记录;遇到 404 或 410 时清除订阅。MDN 的指引简短而准确:应当为用户“提供一种简便的方式,让他们可以选择今后不再接收”。

Web 推送在渠道组合中的位置

Web 推送是一个好的第三渠道,却是一个糟糕的首选渠道:快、边际成本近乎为零、在时间敏感的提醒上无可匹敌,但绑定设备、无法导出,而且离永久失去只差一次点击。

于是编排才是真正的问题。哪条消息走哪个渠道,推送已经带来转化时如何抑制那封邮件,以及在识别方式各不相同的界面之间如何保持对客户的统一视图。Brevo 在邮件和短信之外还提供 Web 与移动推送,而 Tajo 构建在 Brevo 之上,为 Shopify 商店协调这套跨渠道逻辑。短信那一侧可以看短信自动化指南。

关键要点

  • Web 推送是三个 API 的协作:Service Worker 负责后台执行,Push API 负责订阅与传输,Notifications API 负责展示。一次订阅是一个 endpoint 加一把 p256dh 密钥和一个 auth 密钥,负载端到端加密,VAPID 证明发送方身份。
  • 推送自 2023 年 3 月起已是 Baseline 广泛可用,但在 iOS 与 iPadOS 上只对添加到主屏幕的 Web 应用有效。
  • 绝不要在页面加载时请求授权。使用软性预提示,在恰当场景中询问,并记住屏蔽对该来源是永久的。
  • Chrome 现在会执行更安静的提示、速率限制和自动权限撤销,所以发得糟糕会让你失去已有的订阅者。
  • 一次订阅是一个浏览器,不是一个人,而且无法导出。先建起邮件列表,再用推送去加速它。

常见问题

Web 推送通知是怎么工作的?

站点先注册一个 Service Worker,浏览器随后向推送服务创建订阅,并返回一个 endpoint URL 和两个加密密钥,你的服务器再把加密后的负载 POST 到这个 endpoint。推送服务唤醒 Service Worker,由它展示通知。整个过程不需要站点处于打开状态。

Web 推送通知在 iPhone 上能用吗?

能,但只限添加到主屏幕的 Web 应用。Apple 在 iOS 与 iPadOS 16.4 中为主屏幕 Web 应用加入了 Web Push,并且授权请求必须由用户的直接操作触发。在 iOS 上以普通 Safari 标签页打开的站点无法创建订阅。

用户屏蔽通知之后,网站还能再问一次吗?

不能。浏览器会为该来源保存这个决定,之后的授权请求会直接返回已拒绝状态,不再弹出提示。只有用户自己在浏览器设置里才能改回来,而几乎没有人会去改。所以第一次询问实际上是不可逆的。

Web 推送里的 VAPID 是什么?

VAPID 全称是 Voluntary Application Server Identification,由 RFC 8292 定义。你的服务器用一把 ECDSA P-256 私钥签发 JWT,并附上对应的公钥,推送服务据此确认发往某个订阅的推送确实来自创建它的那台服务器。

Web 推送通知的订阅率多少算好?

订阅率会因为提示设计和场景不同而差异极大,任何单一基准数字都值得怀疑。真正有意义的信号是你自己的接受、拒绝、忽略与关闭的比例分布,Chrome 会在 Chrome UX Report 中为符合条件的来源公布这些数据。

Web 推送比邮件更好吗?

它是不同的渠道,不是更好的渠道。推送更快、更短,邮件更丰富、可迁移,而且能触达此刻不在任何已订阅浏览器上的人。推送订阅还绑定在浏览器和设备上而不是人身上,所以无法像邮件列表那样导出或迁移。

Web 推送通知需要 HTTPS 吗?

需要。Service Worker 和 Push API 只能在安全上下文中使用,在生产环境就意味着 HTTPS。浏览器把 http://localhost 视为安全,所以本地开发不需要证书。

GDPR 下 Web 推送需要征得同意吗?

浏览器的授权提示是技术闸门,本身并不构成完整的合法性基础。如果用推送向欧盟境内的人做营销,就要像对待其他直接营销渠道一样:在提示出现前说明你会发什么,保留订阅记录,并让退订变得简单。

每周应该发几条推送通知?

从每周一到三条开始,只有在退订率和点击率保持稳定时才扩大。Chrome 会对高发送量、低互动的站点施加速率限制,而且现在会自动撤销用户已不再互动的站点的通知权限,所以只有量没有相关性会摧毁你辛苦建立的受众。

申请抢先体验

请输入您的名字和公司电子邮箱地址。我们会发送确认 Tajo 访问申请的链接。

获取Brevo