更新于 2016 年 2 月 20 日:推送服务现在需要在对端点的请求中明确包含“TTL”头。文章已更新以反映这一点。更多详细信息请参阅 Mozilla 服务博客。
您是否曾经希望网站能够在发生重要事件时通知您,即使您没有打开该网站?也许您有传入的 WebRTC 通话、即时消息或财务更新。也许您的城市刚刚宣布了紧急扫雪计划。
有时您只想在发生某些事情时知道。
这就是网络推送的功能。它现在已在 Firefox 44 中可用。
网络推送是什么样子的?
只要您的浏览器正在运行,它就可以接收来自网站的通知,即使该网站未打开。这意味着您可以关闭电子邮件选项卡,并在收到新邮件时仍然收到通知。这对内存使用、性能和电池续航时间来说都是巨大的优势。
来自网站的通知与原生通知没有区别,Mozilla 的 Service Worker 食谱中有一些现场演示,您可以亲眼看到这一点。
与地理位置或网络摄像头访问类似,网络推送需要网站在向用户显示通知之前获得明确且可撤销的权限。
隐私方面怎么样?
网络推送通过与充当消息中央中继的推送服务保持持久连接来工作。每个浏览器供应商都运行他们自己的推送服务,并且该服务旨在保护您的隐私
- 为了防止跨站点关联,每个网站都会为您的浏览器提供不同的匿名网络推送标识符。
- 为了阻止窃听,有效负载会被加密到仅由您的浏览器持有的公钥/私钥对。
- 只有在您拥有活动网络推送订阅时,Firefox 才会连接到推送服务。这可能是对网站的订阅,也可能是对 Firefox Hello 或 Firefox Sync 等浏览器功能的订阅。
您始终处于控制之中:推送通知是选择加入的,您可以随时从任何网站撤销权限,方法是从 页面信息面板 或“通知”部分(首选项 → 内容)中撤销。
网络推送是如何工作的?
在今天之前,人们不得不依赖应用程序、电子邮件或短信来及时获取通知。现在网络可以做到这一点。
网络推送是 Service Worker 标准的扩展,这意味着您可以在 Mozilla 的 Service Worker 食谱 中找到网络推送的出色且带注释的演示。MDN 还提供了关于网络推送的 优秀文档,如果您需要直接查看源代码,规范的最新编辑草案位于 GitHub 上。
去年 10 月,Chris Mills 在 Hacks 上撰写了 一篇关于网络推送的精彩介绍,其中解释了 Service Worker 生命周期及其与推送的关系。回顾一下
- 网站可 向浏览器注册 Service Worker。Service Worker 是具有强大功能的小型 JavaScript 程序,例如拦截网络请求或即使在父网站关闭时也能运行。
- Service Worker 注册对象 公开了一个 pushManager 属性。
- 网站使用 pushManager 来 获取现有订阅 或 创建新订阅
- 该 订阅对象 公开了有关订阅的元数据,包括浏览器供应商推送服务上的唯一 端点 URL。
每当网站向该端点发出 POST 请求时,推送服务就会将消息路由到您的浏览器,其中相应的 Service Worker 会收到一个 push 事件。然后,Service Worker 可以 显示通知 或采取其他操作。
对端点的 HTTP POST 请求必须包含“TTL”头,设置为应保存消息的秒数(如果用户不在线)。TTL 到期后,未送达的消息将过期且不会再送达。有关此标头的更多技术信息,请参阅 Mozilla 服务博客。
在代码中,接收事件的 Service Worker 可能如下所示
self.addEventListener('push', function(event) {
event.waitUntil(
self.registration.showNotification('Example Notification', {
body: 'Hello, world!',
})
);
})
同时,注册 Service Worker 并获得显示通知的权限可能类似于下面的代码。
注意:此代码示例使用 ES7 的草案 async/await 语法,因为它读起来最清楚。要在生产环境中使用它,请查看 纯 JavaScript 中的等效代码。
async function registerForPush() {
// Register the Service Worker
let registration = await navigator.serviceWorker.register('service-worker.js');
// Check if we already have a subscription
let subscription = await registration.pushManager.getSubscription();
// If not, try to subscribe.
if (!subscription) {
subscription = await registration.pushManager.subscribe();
}
// Save the subscription data on our website's backend.
await fetch('/save-push-endpoint', {
method: 'post',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(subscription)
});
// Done! Now our backend can send Push messages by POSTing to subscription.endpoint!
}
同样,Service Worker 食谱 中有许多带有带注释源代码的现场演示。如果您感到困惑,请先阅读这些演示。
其他问题
用户的端点 URL 会发生更改吗?
端点可以随时更改。在实践中,这种情况应该很少见,但您应该始终准备好处理 pushsubscriptionchange 事件,并且在每次调用 getSubscription()
或 subscribe()
时都应该检查新的端点。
浏览器的支持情况如何?
在撰写本文时,推送功能适用于桌面版 Firefox,并且 Chrome 部分支持。向 Chrome 推送也需要 一些额外的设置。Microsoft Edge 团队将推送列为 正在考虑中。更多信息请参阅 Can I Use?
如何让用户取消订阅推送?
使用 subscription.unsubscribe() 方法。不要忘记更新您的后端,以便停止向旧端点发送通知。
在实际发生之前,我能否检查 subscribe()
是否会提示用户?
可以!调用 pushManager.permissionState() 会返回一个 Promise,该 Promise 解析为当前的权限状态:"granted"
、"denied"
或 "prompt"
。
请务必在评论中告诉我们您对推送 API 的看法。我们欢迎所有反馈,包括建议、问题和错误报告。
关于 Dan Callahan
Mozilla 开发者关系工程师,前 Mozilla Persona 开发者。
54 条评论