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

liuxuhui發表於2021-09-09

摘要: 如何在Web端推送訊息?

  • 原文:
  • 作者:

經授權轉載,版權歸原作者所有。

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

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

簡介

Web 推送通知允許使用者在 Web 應用程式需要更新時選擇是否接收更新訊息,目的是在重新吸引使用者群注意的更新資訊通常是對使用者來說有趣、重要、實時的內容。

推送通知的基礎是我們 講的 Service Workers。

在這種情況下,使用 Service Worker 的原因是它們在後臺工作。這對於推送通知非常有用,因為這意味著只有當使用者與通知本身進行互動時,它們的程式碼才會被執行。

推送和通知

推送和通知都有各自的 API

  • — 當伺服器向 Service Worker 提供資訊時呼叫它。
  • — 這是 Service Worker 或web應用程式中向使用者顯示資訊的指令碼的操作。

推送 ( Push )

實現 Push 一般的三個步驟:

  • UI — 新增必要的客戶端邏輯來訂閱推送的使用者。這是 Web 應用程式 UI 需要的 JavaScript 邏輯,以便使用者能夠自己註冊來推送訊息。
  • 傳送推送通知 — 在伺服器上實現 API 呼叫,該呼叫觸發到使用者裝置的推送訊息。
  • 接受推送訊息 — 在推送訊息到達瀏覽器時處理它。

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

瀏覽器支援檢測

首先,我們需要檢查當前瀏覽器是否支援推送訊息,可以透過兩個簡單的檢查來判斷是否支援推送訊息:

  • 檢查 navigator 物件上的 serviceWorker
  • 檢查 window 物件上的 PushManager

程式碼如下:

圖片描述

註冊 Service Worker

如果瀏覽器支援該功能,下一步驟就是註冊 Service Worker。

如何註冊 Service Worker,上一篇文章 裡面就有講過了。

請求許可

Service Worker 註冊後,我們就可以開始訂閱該使用者。為此,我們需要得到使用者的許可才能給使用者傳送推送訊息。

獲得許可權的 API 相對簡單,但是缺點是,API 已經 。這就引入了一個問題:我們不知道當前瀏覽器實現了 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 金鑰,它們是伺服器特有的。它們是一對公鑰和私鑰。私鑰秘密儲存在你的終端,而公鑰則與客戶端交換。這些鍵允許推送服務知道哪個應用伺服器訂閱了某個使用者,並確保觸發該使用者的推送訊息的伺服器是同一臺伺服器。

你只需要為應用程式建立一次 私鑰/公鑰對,一種方法是訪問 。

在訂閱使用者時,瀏覽器將 applicationServerKey(公共金鑰)傳遞給推送服務,這意味著推送服務可以將應用程式的公共金鑰繫結到使用者的 PushSubscription

流程大概是這樣的:

  • 載入 Web 應用程式後,透過呼叫 subscribe()方法傳遞伺服器金鑰。
  • 瀏覽器向一個推送服務發出網路請求,該服務將生成一個端點,將該端點與金鑰關聯,並將該端點返回給瀏覽器。
  • 瀏覽器將把這個端點新增到 PushSubscription 物件中,該物件透過 返回 subscribe()promise 得到 。

之後,只要你想推送訊息,都需要建立一個 授權頭(Authorization header),其中包含使用應用伺服器的私鑰簽名的資訊。當推送服務接收到傳送推送訊息的請求時,它將透過查詢已連結到該特定端點的公鑰(第二步)來驗證訊息頭。

PushSubscription 物件

PushSubscription 物件包含向使用者的裝置傳送推送訊息所需的所有資訊,如下:

{
  "endpoint": "",
  "keys": {
    "p256dh":
"BIPUL12DLfytvTajnryr3PJdAgXS3HGMlLqndGcJGabyhHheJYlNGCeXl1dn18gSJ1WArAPIxr4gK0_dQds4yiI=",
    "auth":"FPssMOQPmLmXWmdSTdbKVw=="
  }
}
  • endpoint: 推送服務的 URL,要觸發推送訊息,post請求。
  • keys: 該物件包含用於加密透過推送訊息傳送的訊息資料的值。

一旦使用者被訂閱,並且你有了 PushSubscription 物件,就需要將其傳送到伺服器。在伺服器上,你存對資料庫的訂閱,從現在開始使用它向該使用者傳送推送訊息。

圖片描述

傳送推送訊息

當你想向使用者傳送推送訊息時,首先需要的是推送服務。透過 API 呼叫告訴伺服器你現在需要要傳送什麼資料、向誰傳送訊息以及關於如何傳送訊息的任何標準。通常,這個 API 呼叫是在伺服器上完成的。

推送服務

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

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

推送服務處理所有繁重的任務,比如,如果瀏覽器處於離線狀態,推送服務會在傳送相應訊息之前對訊息進行排隊,等待瀏覽器的再次聯機。

每個瀏覽器都可以使用他們想要的任何推送服務,這是開發人員無法控制的。然而,所有的推送服務都有相同的 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更改、使用者互動、網路請求、未處理的異常和除錯訊息)檢視發生在終端使用者身上的所有事情。

原文:

程式碼部署後可能存在的BUG沒法實時知道,事後為了解決這些BUG,花了大量的時間進行log 除錯,這邊順便給大家推薦一個好用的BUG監控工具。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/756/viewspace-2819899/,如需轉載,請註明出處,否則將追究法律責任。

相關文章