JavaScript是如何工做的:Web推送通知的機制

阿里雲最近在作活動,低至2折,有興趣能夠看看:
https://promotion.aliyun.com/...

爲了保證的可讀性,本文采用意譯而非直譯。javascript

這是專門探索 JavaScript 及其所構建的組件的系列文章的第9篇。html

想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等着你!前端

若是你錯過了前面的章節,能夠在這裏找到它們:java

  1. JavaScript是如何工做的:引擎,運行時和調用堆棧的概述!
  2. JavaScript是如何工做的:深刻V8引擎&編寫優化代碼的5個技巧!
  3. JavaScript如何工做:內存管理+如何處理4個常見的內存泄漏 !
  4. JavaScript是如何工做的:事件循環和異步編程的崛起+ 5種使用 async/await 更好地編碼方式!
  5. JavaScript是如何工做: 深刻探索 websocket 和HTTP/2與SSE +如何選擇正確的路徑!
  6. JavaScript是如何工做的:與 WebAssembly比較 及其使用場景 !
  7. JavaScript是如何工做的:Web Workers的構建塊+ 5個使用他們的場景
  8. JavaScript 是如何工做的:Service Worker 的生命週期及使用場景

推送通知在移動端很是常見。在 Web 端,儘管開發人員對其功能的需求很高,但出於某些緣由,推送通知被引入 Web 的時間比較晚。git

簡介

Web 推送通知容許用戶在 Web 應用程序須要更新時選擇是否接收更新消息,目的是在從新吸引用戶羣注意的更新信息一般是對用戶來講有趣、重要、實時的內容。github

推送通知的基礎是咱們 上一篇 講的 Service Workers。web

在這種狀況下,使用 Service Worker 的緣由是它們在後臺工做。這對於推送通知很是有用,由於這意味着只有當用戶與通知自己進行交互時,它們的代碼纔會被執行。數據庫

推送和通知

推送和通知都有各自的 API編程

  • 推送 — 當服務器向 Service Worker 提供信息時調用它。
  • 通知 — 這是 Service Worker 或web應用程序中向用戶顯示信息的腳本的操做。

推送 ( Push )

實現 Push 通常的三個步驟:segmentfault

  1. UI — 添加必要的客戶端邏輯來訂閱推送的用戶。這是 Web 應用程序 UI 須要的 JavaScript 邏輯,以便用戶可以本身註冊來推送消息。
  2. 發送推送通知 — 在服務器上實現 API 調用,該調用觸發到用戶設備的推送消息。
  3. 接受推送消息 — 在推送消息到達瀏覽器時處理它。

接下來討論更詳細的過程。

瀏覽器支持檢測

首先,咱們須要檢查當前瀏覽器是否支持推送消息,能夠經過兩個簡單的檢查來判斷是否支持推送消息:

  1. 檢查 navigator 對象上的 serviceWorker
  2. 檢查 window 對象上的 PushManager

代碼以下:

圖片描述

註冊 Service Worker

若是瀏覽器支持該功能,下一步驟就是註冊 Service Worker。

如何註冊 Service Worker,上一篇文章 JavaScript 是如何工做的:Service Worker 的生命週期及使用場景 裏面就有講過了。

請求許可

Service Worker 註冊後,咱們就能夠開始訂閱該用戶。爲此,咱們須要獲得用戶的許可才能給用戶發送推送消息。

得到權限的 API 相對簡單,可是缺點是,API 已經 從回調更改成返回 Promise。這就引入了一個問題:咱們不知道當前瀏覽器實現了 API 的哪一個版本,所以必須同時實現和處理這兩個版本,以下:

圖片描述

調用 Notification.requestpermission() 會在瀏覽器顯示以下提示:

圖片描述

一旦權限被授予、關閉或阻塞,咱們將會接收分別對應的一個字符串:granteddefaultdenied

請記住,若是用戶單擊了 Block 按鈕,你的 Web 應用程序將沒法再次請求用戶的權限,直到他們經過更改權限狀態手動 「解除」 你的應用程序的權限,此選項隱藏在設置面板中。

使用 PushManager 訂閱用戶

一旦註冊了 Service Worker 並得到了許可,就能夠在註冊 Service Worker 時經過調用registration.pushManager.subscribe() 訂閱用戶。

整個代碼片斷可以下(包括註冊 Service Worker):

圖片描述

registration.pushManager.subscribe(options) 接受一個 options 對象,它包含必要參數和可選參數:

  • userVisibleOnly: 布爾值,表示返回的推送訂閱將只能被用於對用戶可見的消息。
  • applicationServerKey:推送服務器用來向客戶端應用發送消息的公鑰。該值是應用程序服務器生成的簽名密鑰對的一部分,可以使用在 P-256 曲線上實現的橢圓曲線數字簽名(ECDSA)。能夠是 DOMStringArrayBuffer

你的服務器須要生成一對 application server keys ——這些密鑰也稱爲 VAPID 密鑰,它們是服務器特有的。它們是一對公鑰和私鑰。私鑰祕密存儲在你的終端,而公鑰則與客戶端交換。這些鍵容許推送服務知道哪一個應用服務器訂閱了某個用戶,並確保觸發該用戶的推送消息的服務器是同一臺服務器。

你只須要爲應用程序建立一次 私鑰/公鑰對,一種方法是訪問 https://web-push-codelab.glit...

在訂閱用戶時,瀏覽器將 applicationServerKey(公共密鑰)傳遞給推送服務,這意味着推送服務能夠將應用程序的公共密鑰綁定到用戶的 PushSubscription

流程大概是這樣的:

  • 加載 Web 應用程序後,經過調用 subscribe()方法傳遞服務器密鑰。
  • 瀏覽器向一個推送服務發出網絡請求,該服務將生成一個端點,將該端點與密鑰關聯,並將該端點返回給瀏覽器。
  • 瀏覽器將把這個端點添加到 PushSubscription 對象中,該對象經過 返回 subscribe()promise 獲得 。

以後,只要你想推送消息,都須要建立一個 受權頭(Authorization header),其中包含使用應用服務器的私鑰簽名的信息。當推送服務接收到發送推送消息的請求時,它將經過查找已連接到該特定端點的公鑰(第二步)來驗證消息頭。

PushSubscription 對象

PushSubscription 對象包含向用戶的設備發送推送消息所需的全部信息,以下:

{
  "endpoint": "https://domain.pushservice.com/some-id",
  "keys": {
    "p256dh":
"BIPUL12DLfytvTajnryr3PJdAgXS3HGMlLqndGcJGabyhHheJYlNGCeXl1dn18gSJ1WArAPIxr4gK0_dQds4yiI=",
    "auth":"FPssMOQPmLmXWmdSTdbKVw=="
  }
}
  • endpoint: 推送服務的 URL,要觸發推送消息,post請求。
  • keys: 該對象包含用於加密經過推送消息發送的消息數據的值。

一旦用戶被訂閱,而且你有了 PushSubscription 對象,就須要將其發送到服務器。在服務器上,你存對數據庫的訂閱,從如今開始使用它向該用戶發送推送消息。

圖片描述

發送推送消息

當你想向用戶發送推送消息時,首先須要的是推送服務。經過 API 調用告訴服務器你如今須要要發送什麼數據、向誰發送消息以及關於如何發送消息的任何標準。一般,這個 API 調用是在服務器上完成的。

推送服務

推送服務是接收請求、驗證請求並將推送消息發送到對應的瀏覽器。

請注意,推送服務不是由你管理的——它是一個第三方服務。你的服務器是經過 API 與 推送服務通訊的服務器。推送服務的一個例子是 谷歌的FCM

推送服務處理全部繁重的任務,好比,若是瀏覽器處於脫機狀態,推送服務會在發送相應消息以前對消息進行排隊,等待瀏覽器的再次聯機。

每一個瀏覽器均可以使用他們想要的任何推送服務,這是開發人員沒法控制的。然而,全部的推送服務都有相同的 Api,因此這不會形成實現困難。

爲了得到處理推送消息請求的 URL,須要檢查 PushSubscription 對象中端點的存儲值。

推送服務 API

推送服務 API 提供了一種向用戶發送消息的方法。API 是 Web 協議,它是一個 IETF 標準,定義瞭如何對推送服務進行 API 調用。

使用推送消息發送的數據必須加密。這樣,就能夠阻止推送服務查看發送的數據。這一點很重要,由於瀏覽器決定使用哪一個推送服務(它可能正在使用不受信任且不夠安全的某個推送服務)。

對於每條推送消息,也能夠給出以下說明:

  • TTL  — 定義消息在刪除和未發送以前應排隊多長時間。
  • 優先級 — 定義每一個消息的優先級,推送服務只發送高優先級的消息,確保用戶由於一些突發狀況關機或者斷電等。
  • 主題 — 爲推送消息提供一個主題名稱,該名稱將用相同的主題替換掛起的消息,這樣,一旦設備處於活動狀態,用戶就不會收到過期的信息。

圖片描述

瀏覽器中的推送事件

一旦按照上面的解釋將消息發送到推送服務,該消息將處於掛起狀態,直到發生如下狀況之一:

  • 設備上線
  • 消息因爲 TTL 而在隊列上過時

當推送服務傳遞消息時,瀏覽器將接收它,解密它,並在的 Service Worker 中分派一個 push 事件。這裏最重要的是,即便 Web 頁面沒有打開,瀏覽器也能夠執行你的 Service Worker。流程以下:

  • 推送消息到達瀏覽器,瀏覽器解密它
  • 瀏覽器喚醒 Service Worker
  • push 事件被分發給 Service Worker

設置推送事件監聽器的代碼應該與用 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.');
  }
});

須要瞭解 Service Worker 的一點是,你沒有 Service Worker 代碼運行時長的控制權。瀏覽器決定什麼時候將其喚醒以及什麼時候終止它。

在 Service Worker 中,event.waitUntil(promise),告訴瀏覽器在該promse 未完成以前工做將一直進行中,若是它但願完成該工做,它不該該終止 Sercice Worker。

如下是一個處理 push 事件的例子:

self.addEventListener('push', function(event) {
  var promise = self.registration.showNotification('Push notification!');

  event.waitUntil(promise);
});

調用 self.registration.showNotification() 將向用戶顯示一個通知,並返回一個 promise,該 promise 在顯示通知後將執行 resolve 方法。

showNotification(title, options) 方法能夠根據須要進行可視化調整,title 參數是一個字符串,而參數 options 是一個對象,內容以下:

{
  "//": "Visual 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'>",

  "//": "Behavioural Options",
  "tag": "<String>",
  "data": "<Anything>",
  "requireInteraction": "<boolean>",
  "renotify": "<Boolean>",
  "silent": "<Boolean>",

  "//": "Both Visual & Behavioural Options",
  "actions": "<Array of Strings>",

  "//": "Information Option. No visual affect.",
  "timestamp": "<Long>"
}

能夠了解更多的細節,每一個選項在這裏作什麼- https://developer.mozilla.org...

當有緊急、重要和時間敏感的信息須要與用戶分享時,推送通知是吸引用戶注意力的好方法。

例如,咱們在 SessionStack 計劃利用推送通知讓咱們的用戶知道他們的產品什麼時候出現崩潰、問題或異常。這將讓咱們的用戶當即知道發生了什麼錯誤。而後,他們能夠將問題做爲視頻回放,並利用咱們的庫收集的數據(如DOM更改、用戶交互、網絡請求、未處理的異常和調試消息)查看發生在最終用戶身上的全部事情。

原文:

https://blog.sessionstack.com...

代碼部署後可能存在的BUG無法實時知道,過後爲了解決這些BUG,花了大量的時間進行log 調試,這邊順便給你們推薦一個好用的BUG監控工具 Fundebug

你的點贊是我持續分享好東西的動力,歡迎點贊!

交流

乾貨系列文章彙總以下,以爲不錯點個Star,歡迎 加羣 互相學習。

https://github.com/qq44924588...

我是小智,公衆號「大遷世界」做者,對前端技術保持學習愛好者。我會常常分享本身所學所看的乾貨,在進階的路上,共勉!

關注公衆號,後臺回覆福利,便可看到福利,你懂的。

clipboard.png

相關文章
相關標籤/搜索