我的总结:javascript
1.介绍了网页消息推送通知机制html
全文地址:https://github.com/Troland/how-javascript-worksjava
这是 JavaScript 工做原理的第九章。node
如今让咱们把注意力转移到网页推送通知:咱们将会查看其构造,探索发送/接收通知背后的过程以及最后分享一下咱们在 SessionStack 是如何计划利用这些功能来建立新的产品功能的。git
推送通知这一功能在移动端已经很是广泛。不知为什么,网页端的推送通知是千呼万唤始出来,即便大多数开发者强烈地要求实现这一功能。github
网页推送通知容许用户选择定时从网络应用获取及时信息。它旨在为用户从新获取其感兴趣,重要和及时的信息。web
推送服务是基于服务工做线程的,服务工做线程(service web worker)在以前的文章中有详细阐述过。数据库
这个状况下,之因此采用服务工做线程是由于它会在后台运行,从而不会阻塞界面的渲染。对于推送通知来讲,这是至关重要的,由于这意味着只有当用户和推送通知自己进行交互操做才会执行推送通知的相关代码。promise
消息推送和通知是两个不一样的接口。浏览器
实现消息推送大概有如下三个步骤:
如今,让咱们详细阐述整个过程。
首先,须要检测当前浏览器是否支持消息推送服务。能够采用如下两种简单的检查:
navigator
对象上的 serviceWorker
属性window
对象上的 PushManager
属性都检测代码以下:
if (!('serviceWorker' in navigator)) { // 当前浏览器不支持服务器工做线程,禁用或者隐藏界面 return; } if (!('PushManager' in window)) { // 当前浏览器不支持推送服务,禁用或者隐藏界面 return; }
如今,消息推送功能是支持的。下一下即注册服务工做线程。
从以前的文章中你应该很熟悉如何注册服务工做线程。
当注册服务工做线程以后,接下来进行用户订阅的相关操做。这须要得到用户的受权来向其推送消息。
得到受权的接口至关的简单但有一个缺点即接口 接受的参数之前是一个回调函数如今是一个 Promise。由于没法知晓当前浏览器支持的接口版本,因此须要进行兼容处理。
相似这样:
function requestPermission() { return new Promise(function(resolve, reject) { const permissionResult = Notification.requestPermission(function(result) { // 使用回调来处理废弃的接口版本 resolve(result); }); if (permissionResult) { permissionResult.then(resolve, reject); } }) .then(function(permissionResult) { if (permissionResult !== 'granted') { throw new Error('Permission not granted.'); } }); }
调用 Notification.requestPermission()
会向用户弹出如下的提示框:
当得到,关闭以及禁止权限的时候,就能够获得 granted
,default
或者 denied
的结果字符串。
须要注意的是当用户点击 禁止
按钮,网络应用将不会再次询问用户受权直到用户手动开启更改受权状态。该选项隐藏于设置面板中。
点击地址栏最左边的信息按钮便可弹出受权的弹窗。
一旦服务工做线程注册成功且得到受权,就能够在注册服务器线程的时候经过调用 registration.pushManager.subscribe()
来订阅用户。
整个代码片段以下(包括注册服务工做线程):
function subscribeUserToPush() { return navigator.serviceWorker.register('service-worker.js') .then(function(registration) { var subscribeOptions = { userVisibleOnly: true, applicationServerKey: btoa( 'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U' ) }; return registration.pushManager.subscribe(subscribeOptions); }) .then(function(pushSubscription) { console.log('PushSubscription: ', JSON.stringify(pushSubscription)); return pushSubscription; }); }
registration.pushManager.subscribe(options)
中有一个 options 对象参数,其中包含有必须或者可选的参数:
true
不然会出错(这是历史缘由形成的)。DOMString
字符串或者 ArrayBuffer
,消息推送服务器用来验证应用服务器。消息推送服务器须要生成一对应用服务器密钥对-即 VAPID 密钥对,这对于消息推送服务器来讲是惟一的。它们是由一对公钥和私钥所组成的。私钥秘密存储于推送服务器端,公钥用来和客户端进行交换通信用的。这些密钥让推送服务辨别订阅用户的应用服务器以及确保触发推送消息到指定用户的是同一个应用服务器。
你只须要一次性生成应用程序私有/公有密钥对。能够访问 https://web-push-codelab.glitch.me/ 生成密钥对。
当订阅用户的时候,浏览器向推送服务传入 applicationServerKey
(公钥),意即推送服务把应用服务器公钥和用户的 PushSubscription
绑定在一块儿。
过程以下:
subscribe
,传入服务器公钥。subscribe()
promise 所返回的 PushSubscription
对象中。以后,每当须要推送信息的时候,必须发送一个认证头其中包含应用服务器私钥签名的信息。
每当推送服务接收到推送消息的请求,它会经过在传输头中查找已经和指定端(第二步中)绑定的公钥来进行验证。
PushSubscription
包含了向用户设备推送信息所必备的一切信息。大概包含以下信息:
{ "endpoint": "https://domain.pushservice.com/some-id", "keys": { "p256dh": "BIPUL12DLfytvTajnryr3PJdAgXS3HGMlLqndGcJGabyhHheJYlNGCeXl1dn18gSJ1WArAPIxr4gK0_dQds4yiI=", "auth":"FPssMOQPmLmXWmdSTdbKVw==" } }
endpoint
便是推送服务地址。当须要推送消息时,向该地址发起 POST 请求。
keys
对象包含用来加密随推送消息一块儿发送的信息数据的值。
当用户订阅以后且返回了 PushSubscription
对象,你须要把它保存在推送服务器上。这样就能够把该订阅相关数据保存在数据库之中而后从今之后,就能够根据数据库中的存储值来给指定的用户发送消息。
当须要发送消息到用户的时候,首先须要有一个消息推送服务。你通知推送服务(经过接口调用)须要推送的数据,消息推送的目标用户以及任意条件下如何发送消息。通常状况下,这些接口调用是由消息推送服务器来完成的。
消息推送服务是用来接收消息推送请求,验证请求以及推送消息到指定的用户浏览器端。
请注意这里的消息推送服务并非由你来控制的-它是第三方服务。服务器只是经过接口来和消息推送服务进行通信。Google’s FCM 是消息推送服务之一。
消息推送服务会处理核心的事务。好比,当浏览器离线,推送服务在发送各自的消息以前会排队消息且等待直到浏览器连网。
开发人员能够选择让浏览器使用任意的消息推送服务。
然而,全部的消息推送服务都拥有同样的接口,这样就不会因为接口不一而增长消息推送实现的难度。
能够从 PushSubscription
对象的 endpoint
属性值得到处理消息推送的请求 URL 地址。
消息推送服务接口提供了向用户发送消息的一种方法。该接口是一个被称为 Web Push Protocol 的 IETF 标准协议,里面定义了如何调用消息推送服务。
推送的消息必须得加密。这样能够防止消息推送服务窥视到发送的数据。这是相当重要的由于客户端能够决定使用哪一个消息推送服务(可能会使用一些不被信任和不安全的消息推送服务)。
消息推送参数:
每当发送消息到如上的推送服务,消息会处于待发送状态直到发生如下几种状况:
当消息推送服务传输消息到浏览器,浏览器会接收到,解密,而后分派给服务工做线程 push
事件。
划重点这里即便没有打开网页,浏览器仍然能够执行服务工做线程。会发生以下事件:
push
事件。监听推送事件和在 JavaScript 中写的其它事件监听很是相似。
self.addEventListener('push', function(event) { if (event.data) { console.log('This push event has data: ', event.data.text()); } else { console.log('This push event has no data.'); } });
须要理解服务工做线程的一点即其运行时间是不可人为控制的。只有浏览器能够唤醒和结束它。
在服务工做线程中,event.waitUntil(promise)
告诉浏览器服务工做线程正在处理消息直到 promise 解析完成,若是想要完成消息的处理,那么浏览器就不该该停止服务工做线程。
如下为处理 push
事件的示例:
self.addEventListener('push', function(event) { var promise = self.registration.showNotification('Push notification!'); event.waitUntil(promise); });
调用 self.registration.showNotification()
向用户弹出一个通知而且返回一个 promise,一旦通知显示完成即解析完成。
能够采用可视化的方法来设置符合本身需求的 showNotification(title, options)
方法。title
参数是字符串而 options 是一个相似以下的对象:
{ "//": "视觉选项", "body": "<String>", "icon": "<URL String>", "image": "<URL String>", "badge": "<URL String>", "vibrate": "<Array of Integers>", "sound": "<URL String>", "dir": "<String of 'auto' | 'ltr' | 'rtl'>", "//": "行为选项", "tag": "<String>", "data": "<Anything>", "requireInteraction": "<boolean>", "renotify": "<Boolean>", "silent": "<Boolean>", "//": "视觉和行为选项", "actions": "<Array of Strings>", "//": "信息选项。没有视觉效果", "timestamp": "<Long>" }
能够在这里查看到每一个选项的更加详细的内容。
每当想要和用户分享紧急,重要及紧迫的信息的时候,消息推送服务是用来通知用户的一个绝佳的方式。
服务工做线程能够采用相似以下的代码来进行处理:
self.addEventListener('notificationclick', function(event) { console.log('[Service Worker] Notification click Received.'); event.notification.close(); event.waitUntil(clients.openWindow('https://developers.google.com/web/')); });
nodejs 可使用这里的库来构建推送服务器。
作一个网页消息推送所须要的条件即:
一张流程图来表示吧: