前言
该文章翻译自web.dev的Notifications系列文章,本篇文章原文链接点击这里
什么是推送通知
消息推送允许你推送消息给用户,即使用户没有在浏览你的网站。这个技术之所以被称为消息推送,是因为你可以推送信息给用户,从概念上它区别于主动获取消息的技术。
通知展示一段信息给用户,网站可以使用通知技术来告诉用户一些重要的、紧急的事件,或者提示用户需要执行的动作。不同的平台,通知的形式各不相同。
消息推送和通知其实是两个独立,但又相互补充的技术。推送技术指的是你可以从服务器向用户发送消息,即使用户并没有在使用你的网站。通知技术指的是在用户的设备上展示推送的信息。我们可以使用通知技术展示信息,不仅限于推送消息。那反过来,我们可以静默推送,而不使用通知功能来告知用户吗?答案是否定的,或许未来有一天是可以的,但是目前浏览器还不允许这么做。即目前通过消息推送技术获取的信息,必须显式的通知用户。非技术用户可能不明白消息推送和通知之间的区别。在这篇文章中我们提到推送通知(push notifications)时,我们指得是消息推送和通知两种技术,当我们提到消息推送(push messages)时,指得是推送技术本身,当我们说到通知(notifications)时,指得仅仅是通知技术。
为什么要使用推送通知?
- 对用户来说,推送通知可以定时接收到有价值、准确的信息
- 对网站开发者来说,推送通知时增加网站用户粘性的方式之一
推送通知时如何工作的
在一个更高的纬度来看,实现推送通知主要包含一下几个关键步骤:
- 在客户端实现代码逻辑来获取通知相关的用户权限。然后将授权后获得的客户端标识发送给服务器并存储在数据库中。
- 在服务端实现向客户端发送消息的逻辑。
- 在客户端添加逻辑:接收上一步推送给客户端设备的消息,并通过通知技术展示给用户。
下面将详细解释上面的几个步骤。
获取推送通知权限
首先,网站需要获得用户的授权,来推送通知。这个动作必须由用户触发,例如点击询问提示框的确认按钮,确认之后,我们需要调用Notification.requestPermission()
,操作系统或者浏览器会展示某种形式的UI来正式通知询问用户是否给予授权。授权弹框的UI在各个平台上各不相同。
客户端订阅推送通知
得到用户的授权之后,网站必须在JavaScript中,利用Push API初始化订阅推送。在这个过程中,你必须提供一个公钥,后面将会详细解释公钥。发起订阅过程时,浏览器向推送服务器发送一次网络请求,这个后面也会详细解释这个过程。
以上步骤成功之后,浏览器会返回PushSubscription
对象,你必须将这个对象保存下来,通常是将这个对象发送给后端服务器并存储在数据库当中。
发送消息
你的服务器并不会直接向客户端发送消息,而是由推送服务(push service)来实现这个过程。推送服务由浏览器厂商控制。当你发送通知给客户端时,你需要向推送服务发起网络请求,这个请求被称之为web push protocol request,web push protocol request包含以下几部分:
- 要发送的数据
- 要发送给哪个客户端
- 一些指令,用来指定消息的交付模式,例如指定推送服务应该在十分钟之后停止再次尝试发送消息。
通常这个请求是在网站的服务端发起的。当然,你不需要从零开始构建这个请求,已经有很多库可以帮你实现这个功能。如web-push-libs,这个过程主要是通过HTTP来实现的。
推送服务收到请求后,经过认证,将会把消息发送给正确的客户端。如果浏览器是离线状态,推送服务将会把消息放入队列中,直到浏览器恢复在线状态。
推送服务是由浏览器厂商指定的,网站开发者不能指定它。不过用户并不需要关心,因为所有的推送服务都必须遵守推送协议。你只需要按照协议的规范,在服务端发送正确的请求即可。根据规范,这个请求需要带上特殊的请求头,数据必须以字节流的形式发送。
你需要关注的是向推送服务发送正确的请求,订阅推送成功后,浏览器会返回给你一个PushSubscription
对象,该对象包含了有关推送服务的信息:
1 | { |
endpoint字段域名指得就是推送服务的地址,endpoint
字段的路径是客户端的唯一标识,它用来帮助推送服务将消息准确的发送给客户端。keys
字段是用来加密信息的,这个稍后也会讲到。
推送消息加密
发送给推送服务的数据必须是经过加密的,这能保证即使是推送服务也不能查看你要发送给客户端的数据。这是因为推送服务是由浏览器厂商决定的,理论上也是不安全的。你的服务器必须使用PushSubscription
提供的keys
字段加密你要发送给推送服务的请求数据。
加密推送服务请求
推送服务提供一种特别的方式来阻止其他人像你的客户发送请求。严格来说你不需要关注这个,但在Chrome浏览器上是必须的,浏览器提供一种简便的方式来处理加密,在Firefox这是可选的。其他浏览器在未来可能也会支持该选项。
加密过程需要你的服务器提供唯一的公钥和私钥对。认证的大致流程如下:
- 生成唯一的包含公钥和私钥的密钥对。该密钥对就是我们所说的应用服务密钥application server keys,它也被称为VAPID keys,VAPID是一个规范,定义了这个认证的过程。
- 当你在JavaScript代码中订阅推送通知时,你需要提供公钥,然后推送服务会为该订阅设备生成一个
endpoint
,该endpoint
和你提供的公钥的建立关联关系。 - 当你在服务端向推送服务发送请求时,需要使用私钥对你发送的JSON数据进行签名加密。
- 当推送服务收到该请求时,会使用已存储的公钥对加密的数据进行认证。如果认证成功,推送服务就能知道这个请求来自之前已经订阅的某个网站用户。
自定义推送消息
web推送协议规范定义了一些参数,允许你指定消息的推送方式,例如:
- 消息的生命周期(Time-To-Live,TTL)定义了推送服务分发消息的时长。
- 消息的紧急程度,这对向发送更高优先级的消息很有用。
- 消息的主题,他会替代还未正式发送的,有相同主题的消息。
以通知的形式展示推送消息
一旦你向推送服务发送请求,推送服务会将你的消息放入队列,直到发生以下事件发生:
- 客户端上线状态,推送服务将消息分发给客户端
- 消息过期
当客户端浏览器收到推送的消息,会对推送的消息数据进行解密,并触发Service Worker的push
事件,service worker是运行在后台的JavaScript代码,即使用户关闭了你的网站,甚至关闭了浏览器。在service worker push事件的回调函数中,你需要调用ServiceWorkerRegistration.showNotification()
以通知的形式展示收到的消息。