第十一篇:FAQ
原文地址:FAQ
譯文地址:FAQ
譯者:劉鵬
為什麼推送在瀏覽器關閉的時候不工作
這個問題頗有爭議,主要是因為有一些場景使得這個問題比較難以追因和理解。
讓我們先從 Android 開始。Android 系統被設計成監聽推送訊息,一旦收到一條訊息,就會喚醒對應的 Android 應用來處理推送訊息,而不管這個應用是否關閉。
Android 上的任何瀏覽器和上述應用的表現是一致的,當接收到一條推送訊息的時候,瀏覽器會被喚醒,然後瀏覽器再喚醒你的 service worker,發出推送事件。
桌面作業系統則有細微差別。其中 Mac OS X 系統是最容易理解的,因為有一個視覺化的標記來輔助解釋不同的場景。
在 Mac OS X 系統上,你可以從 dock (列表中)的應用 icon 下方的標記來判斷一個程式是否在執行。
如果你對比一下下面 dock 中的兩個 Chrome icon,通過 icon 下面的標記我們可以知道左邊的那個正在執行,然而右邊的那個 Chrome 沒有在執行,因為缺少了下面的標記。
在桌面系統上接收推送訊息的情況下,當瀏覽器在執行的時候(即在 icon 下面有一個標記),你可以接收到訊息。
這意味著即使瀏覽器視窗沒有開啟,你仍然可以在你的 service worker 當中接收到推送訊息,因為瀏覽器正在後臺執行。
推送不能接收到的唯一情況就是瀏覽器被完全關閉了,即完全不在執行( icon 下沒有標記)。這同樣適用於 Windows 作業系統,雖然在 Windows 上判斷 Chrome 是否在後臺執行有一點複雜。
我如何讓使用者在點選推送訊息後,能夠全屏開啟我新增到桌面的 Web App?
在 Android 系統的 Chrome 瀏覽器上,Web App 可以被新增到桌面。當它在桌面被開啟的時候,可以在沒有位址列的全屏模式開啟,就像下面顯示的那樣。
為了保持體驗的一致性,開發者也想使用者在點選通知之後能夠全屏開啟他們的 Web App。
Chrome 在某種程度上實現了這個特性,雖然你可能發現它不太靠譜並且難以追因。相關的實現細節如下:
在 Android 系統上,新增到桌面的網站在點選推送訊息的時候,應該被允許以 standalone(獨立) 模式開啟。然而即使網站被新增到了桌面,由於 Chromium 依然不能檢測到這些網站是否在桌面上。我們啟發式地採用了下面這種方法:那些在最近 10 天內從桌面啟動過的網站,點選通知後將以 standalone 模式開啟。– Chrome Issue
這就意味著,除非你的使用者足夠頻繁地通過桌面訪問你的站點,否則的話你的通知只會開啟一個普通的瀏覽器 UI。
這個問題將進一步解決。
注意: 這個只是 Chrome 的表現,其它瀏覽器也會有一些不同。如果你有任何需要討論的,請儘管提出 issue。
為什麼這個比 web sockets 要好?
即使瀏覽器視窗是關閉的,service worker 依然可以工作。而 web socket 只有在瀏覽器和網頁保持開啟的狀態下才能正常工作。
GCM、 FCM、 Web 推送 和 Chrome 是怎麼回事?
這個問題有很多方面,最簡單的解釋方法是逐步介紹 Web 推送和 Chrome 的歷史。(別擔心,很短)
2014 年 12 月
當 Chrome 首次實現 Web 推送時,是使用 Google Cloud Messaging(GCM)來支援從伺服器向瀏覽器傳送推送訊息的。
但這不是 Web 推送。早期的 Chrome 和 GCM 並不是“真正的” Web 推送有以下幾個原因:
- GCM 要求開發人員在 Google Developers Console 上註冊帳戶。
- Chrome 和 GCM 需要一個特殊的由 Web 應用程式共享的傳送者 ID,來正確地設定訊息。
- GCM 的伺服器接收的是自定義的 API 請求,而非 Web 標準。
2016 年 7 月
7月,Web 推送中的一項新功能釋出 – Application Server Keys(即規範中的 VAPID )。Chrome 在支援此新 API 時,棄用了 GCM,改用 Firebase Cloud Messaging(FCM)作為訊息傳遞服務。這很重要,原因如下:
- Chrome 和 Application Server Keys 不需要使用 Google 或 Firebase 設定任何型別的專案,就可以正常工作。
- FCM 支援 Web 推送協議,這是所有 Web 推送服務都支援的 API。這意味著無論瀏覽器使用什麼推送服務,你只需傳送相同型別的請求,它就會推送訊息。
為什麼現在令人困惑?
現在已經存在的關於 Web 推送的內容中存在大量混淆,其中大部分內容都引用了 GCM 或 FCM。 如果內容用了 GCM,你可以將其視為是過時內容的標誌,或者它太過針對於 Chrome。(我在一些舊的文章中也犯了這個錯誤)
因此,你應該將 Web 推送視為瀏覽器的一部分,瀏覽器使用推送服務來管理髮送和接收訊息,其中推送服務將接受符合“Web 推送協議”的請求。如果按照這樣進行思考,你就可以無視瀏覽器及其使用的推送服務的干擾,並直接開始工作了。
本書的編寫專注於 Web 推送的標準方法,所以有意忽略其他任何內容。
Firebase 有一個 JavaScript SDK,它是什麼以及為什麼會存在?
對於那些已經發現 Firebase Web SDK 且注意到它有 JavaScript 版本的訊息傳遞 API 的人,可能會想知道它與 Web 推送的區別。
訊息傳遞 SDK(Firebase Cloud Messaging JS SDK)在幕後做了一些工作以便更輕鬆地實現 Web 推送。
- 只需要關心 FCM 令牌(僅僅是一個字串),而不必關心
PushSubscription
及其各個欄位。 - 通過使用每個使用者的令牌,你可以使用專有的 FCM API 來觸發推送訊息。此 API 不需要加密有效負載,可以在 POST 請求 body 中傳送普通(未加密)的文字有效載荷。
- FCM 的專有 API 支援自定義功能,例如 FCM 主題(儘管相關文件很少,但它也可以在 Web 上執行)。
- 最後,FCM 支援 Android、iOS 和 Web,因此對於一些團隊來說,在現有專案中更容易使用。
其實它在底層使用的還是 Web 推送,但是目的就是把 Web 推送抽象出來。
就像我在上一個問題中所說的那樣,如果將 Web 推送視為瀏覽器加上推送服務,那麼你可以將 Firebase 中 的 Messaging SDK 視為一個簡化的 Web 推送的庫。
第十一篇:Web 推送:常見問題以及錯誤反饋
譯文地址:Web 推送:常見問題以及錯誤反饋
譯者:劉文濤
當你使用網路推送遇到問題時,可能很難去除錯這個問題或尋求幫助。 本文將概述一些常見問題以及如果你在 Chrome 或 Firefox 中發現錯誤,應該怎麼去做。
在我們深入除錯推送之前,你可能遇到 service workers 本身的問題,檔案未更新,未註冊或一般的異常行為。 關於除錯 service workers 的文件非常完善,如果你是初次使用 service worker 開發的話 ,我強烈建議你去閱讀一下。
在開發和測試 Web 推送的兩個階段中,每個階段都遇到獨有的一些常見問題。
- 傳送訊息: 首先應確保傳送訊息成功。正確返回的 HTTP 狀態碼應該是 201。 如果不是:
- 檢查授權錯誤: 如果收到授權錯誤訊息,請參閱下面 “授權相關問題部分”。
- 其他API錯誤: 如果收到非201狀態程式碼,請參閱下面的“HTTP 狀態程式碼部分“以獲取有關問題原因的指導。
- 接收訊息: 如果你能夠成功傳送訊息,但在瀏覽器上未收到訊息:
- 檢查加密問題: 請參閱下面的“有效負載加密問題部分“。
- 檢查連線問題: 如果是在 Chrome 上出的問題,可能與連線有關。 可參閱下面的“連線問題”部分。
如果無法傳送和接收推送訊息,並且本文件中的相關部分不能幫助你除錯問題,那麼你可能發現了推送機制本身的一個 Bug。在這種情況下,請參閱 “如何提交錯誤報告”部分,提交一份包含所有重要資訊的錯誤報告,以加快錯誤修復過程。
在提交錯誤報告之前我想說的一件事是:Firefox 和 Mozilla 自動推送服務給了很多有用的錯誤資訊。 如果你遇到問題並且不確定是什麼問題的時候,那麼請在 Firefox 中進行測試,看看是否可以收到了更有用的錯誤訊息。
授權問題
授權問題是開發人員在開始使用 Web 推送時遇到的最常見問題之一。 這通常是配置站點應用伺服器金鑰(又名 VAPID 金鑰)的問題。
在 Firefox 和 Chrome 中,支援推送的最簡單方法是在 subscribe()
呼叫中提供 applicationServerKey
。這樣做不好的是,前端和伺服器金鑰之間的任何差異都會導致授權錯誤。
在 Chrome + 雲訊息傳遞FCM
對於使用 FCM 作為推送服務的 Chrome,你將收到來自 FCM:關於UnauthorizedRegistration
response【未經授權註冊】 的一系列不同的錯誤,所有錯誤都涉及應用程式伺服器金鑰。
在以下任何一種情況下,你都會收到一個 UnauthorizedRegistration
錯誤:
- 沒有在 FCM 的請求中定義
Authorization
header。 - 用於訂閱使用者的應用程式金鑰與用於簽署 Authorization header 的金鑰不匹配。
- 你的 JWT【Json web token】到期無效,即超過 24 小時或 JWT 已過期。
- JWT 異常或值無效。
完整的錯誤響應如下所示:
<HTML>
<HEAD>
<TITLE>UnauthorizedRegistration</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
<H1>UnauthorizedRegistration</H1>
<H2>Error 400</H2>
</BODY>
</HTML>
複製程式碼
如果你在 Chrome 中收到此錯誤訊息,可以考慮在 Firefox 中進行測試,看看它是否能夠提供有關此問題的更多資訊。
Firefox and Mozilla 自動推送
Firefox 和 Mozilla 自動推送 為 Authorization
授權問題提供了一系列非常友好的錯誤提示。
如果你的推送請求中未包含 Authorization
header,你將會收到來自 Mozilla 自動推送的 Unauthorized
未授權的錯誤資訊。
{
"errno": 109,
"message": "Request did not validate missing authorization header",
"code": 401,
"more_info": "http://autopush.readthedocs.io/en/latest/http.html#error-codes",
"error": "Unauthorized"
}
複製程式碼
如果 JWT 的已過期,你將會收到一條 Unauthorized
未授權的錯誤資訊,該資訊說明該令牌已過期。
{
"code": 401,
"errno": 109,
"error": "Unauthorized",
"more_info": "http://autopush.readthedocs.io/en/latest/http.html#error-codes",
"message": "Request did not validate Invalid bearer token: Auth expired"
}
複製程式碼
如果使用者訂閱時的應用伺服器金鑰和授權 header 頭簽名時的應用伺服器金鑰不同,則會返回未找到錯誤
{
"errno": 102,
"message": "Request did not validate invalid token",
"code": 404,
"more_info": "http://autopush.readthedocs.io/en/latest/http.html#error-codes",
"error": "Not Found"
}
複製程式碼
最後,如果你的的 JWT 中有無效值(例如,“alg” 值是一個異常的值),你將會從 Mozilla 自動推送中收到以下錯誤資訊:
{
"code": 401,
"errno": 109,
"error": "Unauthorized",
"more_info": "http://autopush.readthedocs.io/en/latest/http.html#error-codes",
"message": "Request did not validate Invalid Authorization Header"
}
複製程式碼
HTTP 狀態碼
有一系列的問題可能導致推送服務返回非 201 響應程式碼。 下面是相關 HTTP 狀態碼列表及其與 Web 推送相關的問題描述。
Status Code | Description |
---|---|
429 | 請求太多。 應用程式伺服器推送服務達到了速率限制。 推送服務的響應當中應該包括了 “Retry-After” 標頭,來指示你需要等待多久來傳送另一個請求。 |
400 | 無效的請求。 你的某一個 Header 無效或格式不正確。 |
404 | 沒有找到。訂閱已過期。在這種情況下,你應該從你的後臺刪除 PushSubscription,並且等待一個時機再次給使用者訂閱。 |
410 | 失效. 訂閱不再有效,應該從你的後臺移除。這可以在 `PushSubscription` 上通過呼叫 `unsubscribe()` 方法來移除。 |
413 | 有效載荷大小太大。 推送服務必須支援的最小大小有效負載是 4096 位元組(或4kb)。 任何更大的大小都可能導致此錯誤。 |
如果 http 狀態碼不在此列表中且錯誤資訊沒有給到幫助,可以檢視 Web Push Protocol
spec (Web 推送協議),看下這個狀態碼是在哪些場景下觸發。
有效負載加密問題
如果成功觸發推送訊息(即向 Web 推送服務傳送訊息並接收到 201 響應碼),但推送事件沒有在 service worker 中觸發,這通常表示瀏覽器無法解密其接收到的訊息。
如果是這種情況,可以在 Firefox 的 DevTools 控制檯中看到一條錯誤訊息,如下所示:
要檢查 Chrome 中是否存在此問題,請執行以下操作:
- 位址列輸入 chrome://gcm-internals ,進入並點選“Start Recording【開始錄製】”按鈕。
- 觸發一個推送訊息,看下“訊息解密失敗日誌”。
如果有效負載的解密存在問題,將看到類似於上面顯示的錯誤。 (請注意詳細資訊列中的 AES-GCM decryption failed
訊息。)
如果是這個問題,有一些工具可以幫助你除錯加密:
連線問題
如果你沒有在 service worker 中收到推送事件,並且沒有看到任何解密錯誤,可能是瀏覽器無法連線到推送服務。
在 Chrome 中,可以通過頁面:chrome://gcm-internals
中的“接收訊息日誌”模組來檢查瀏覽器是否正在接收訊息。
如果沒有及時看到訊息,請確保你的瀏覽器的連線狀態為 CONNECTED
,如下圖所示:
如果連結狀態不是 “CONNECTED”,可能需要刪除當前的配置檔案並建立一個新的。 如果仍然無法解決問題,請按照下面章節的建議提出錯誤報告。
錯誤反饋
如果上面的方式都不能解決你的問題,並且沒有跡象表明問題可能是什麼,請根據你遇到問題的瀏覽器提出問題:
對於 Chrome,你可以在此處反饋問題:bugs.chromium.org/p/chromium/…
對於 Firefox,你可以在此處反饋問題: bugzilla.mozilla.org/
如何提供一個好的的錯誤報告,你應該做到以下幾點:
- 你測試的瀏覽器版本(例如 Chrome 版本50,Chrome 版本51,Firefox 版本50,Firefox 版本51)。
- 給出一個例子,可以重現這個問題;
- 報告中應該包括請求的所有資訊(即對推送服務的網路請求的內容[包含 header])。
- 報告中應該包括網路請求的返回的響應資料。
如果你能提供一個可重現的例子,或者原始碼或託管網站,它經常可以讓我們更快速地診斷和解決問題。