日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

PWA(Progressive Web App)入门系列:Push

發(fā)布時(shí)間:2023/12/9 编程问答 54 豆豆
生活随笔 收集整理的這篇文章主要介紹了 PWA(Progressive Web App)入门系列:Push 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前言

很多時(shí)候,原生應(yīng)用會(huì)通過一些消息推送來喚起用戶的關(guān)注,增加駐留率。網(wǎng)頁(yè)該怎么做呢?有沒有類似原生應(yīng)用的推送機(jī)制?推送功能又能玩出什么花樣呢?


Push API

Push API 給與了 Web 應(yīng)用程序接收從服務(wù)器發(fā)出的推送消息的能力,無(wú)論 Web 應(yīng)用程序是否在用戶設(shè)備前臺(tái),甚至剛加載完成。這樣,開發(fā)人員就可以向用戶投放異步通知和更新,從而讓用戶能更及時(shí)地獲取新內(nèi)容。

對(duì) Web 應(yīng)用來說,要想使用推送,必須在應(yīng)用下的 ServiceWorker 處于激活狀態(tài),在 ServiceWorkerRegistration scope 下的 PushManager 來做推送訂閱相關(guān)工作。

在 ServiceWorkerGlobalScope scope 下通過 onpush 來監(jiān)聽推送事件。

激活一個(gè) service worker 來提供推送消息會(huì)導(dǎo)致資源消耗的增加,尤其是電池。不同的瀏覽器對(duì)此有不同的方案——目前為止還沒有標(biāo)準(zhǔn)的機(jī)制。Firefox 允許對(duì)發(fā)送給應(yīng)用的推送消息做數(shù)量限制(配額)。該限制會(huì)在站點(diǎn)每一次被訪問之后刷新。相比之下,Chrome 選擇不做限制,但要求站點(diǎn)在每一次消息到達(dá)后都顯示通知,這樣可以讓用戶確認(rèn)他們?nèi)韵M邮障⒉⒋_保用戶可見性。

接口

Push 的相關(guān)接口:

  • PushManager
  • PushEvent
  • PushMessageData
  • PushSubscription
  • PushSubscriptionOptions

PushManager

PushManager 接口用于操作推送訂閱。

通過 ServiceWorkerRegistration.PushManager獲取。

方法:

subscribe()

用于訂閱推送服務(wù)。

返回一個(gè) Promise 形式的 PushSubscription 對(duì)象,該對(duì)象包含了推送訂閱詳情。如果當(dāng)前 service worker 沒有已存在的訂閱,則會(huì)創(chuàng)建一個(gè)新的推送訂閱。

語(yǔ)法:

?PushManager.subscribe(options).then(function(pushSubscription) { ... } );

參數(shù):

options:

  • userVisibleOnly:布爾值,表示返回的推送訂閱將只能被用于對(duì)用戶可見的消息。在訂閱時(shí)必須把此項(xiàng)設(shè)置為 true,這樣當(dāng)有消息推送給用戶時(shí),瀏覽器會(huì)展示一個(gè)消息通知,也就是說不存在靜默推送。為了讓用戶可知。
  • applicationServerKey:推送服務(wù)器用來向客戶端應(yīng)用發(fā)送消息的公鑰。該值是應(yīng)用程序服務(wù)器生成的簽名密鑰對(duì)的一部分,可使用在 P-256 曲線上實(shí)現(xiàn)的橢圓曲線數(shù)字簽名(ECDSA)。這里使用的是 VAPID 協(xié)議,VAPID 是 Voluntary Application Server Identification (自主應(yīng)用服務(wù)器標(biāo)識(shí)) 的簡(jiǎn)稱。所以需要將 Base64 的公鑰轉(zhuǎn)為 Uint8 的數(shù)組。

觸發(fā)推送時(shí),瀏覽器的表現(xiàn):

Base64 轉(zhuǎn) Uint8

function base64UrlToUint8Array(base64UrlData) {const padding = '='.repeat((4 - base64UrlData.length % 4) % 4);const base64 = (base64UrlData + padding).replace(/\-/g, '+').replace(/_/g, '/');const rawData = window.atob(base64);const buffer = new Uint8Array(rawData.length);for (let i = 0; i < rawData.length; ++i) {buffer[i] = rawData.charCodeAt(i);}return buffer; }

getSubscription()

用于獲取訂閱對(duì)象 PushSubscription。

它返回一個(gè) Promise 用來處理一個(gè)包含已經(jīng)發(fā)布的分支的細(xì)節(jié)的PushSubscription 對(duì)象。如果沒有已經(jīng)發(fā)布的分支存在,返回null。

語(yǔ)法:

?PushManager.getSubscription().then(function(pushSubscription) { ... } );

permissionState()

用于獲取 PushManager 的權(quán)限狀態(tài)。

語(yǔ)法:

PushManager.permissionState(options).then(function(PushMessagingState) { ... });

參數(shù):

options:

  • userVisibleOnly
  • applicationServerKey

返回 Promise,如下值:

  • granted:WEB 應(yīng)用已授權(quán) Push 權(quán)限。
  • denied:WEB 應(yīng)用已拒絕 Push 權(quán)限。
  • prompt:WEB 應(yīng)用未授權(quán) Push 權(quán)限。

如下使用:

ServiceWorkerRegistration.pushManager.permissionState({userVisibleOnly: true})

PushEvent

Push API 接收消息時(shí)的事件。此事件在 ServiceWorkerGlobalScope 下響應(yīng)。

屬性

data:返回對(duì) PushMessageData 類型,包含發(fā)送到的數(shù)據(jù)的對(duì)象。

PushMessageData

此接口為 PushEvent.data 中的類型。

與 Fetch 中 Body 的方法相似,不同處再于可以重復(fù)調(diào)用。

方法

  • arrayBuffer()
  • blob()
  • json()
  • text()

PushSubscription

PushSubscription 為 PushManager.subscribe() 的訂閱信息類型。

屬性

  • endpoint:包含訂閱相關(guān)的推送服務(wù)器的信息。以 URL 形式展示。最好對(duì)于這個(gè) URL 安全,防止被其他人劫持它并濫用推送功能。
  • expirationTime:返回與推送訂閱關(guān)聯(lián)的訂閱到期時(shí)間(如果有),否則返回null。
  • options:PushSubscriptionOptions 類型,訂閱時(shí)的 options 信息,包含:
    • applicationServerKey
    • userVisibleOnly

方法

getKey()

用于獲取 PushSubscription 中訂閱的公鑰信息,返回 ArrayBuffer。

語(yǔ)法:

?var key = subscription.getKey(name);

參數(shù):

name:

  • p256dh:P-256曲線上的橢圓曲線Diffie-Hellman公鑰(即NIST secp256r1橢圓曲線)。 生成的密鑰是ANSI X9.62格式的未壓縮點(diǎn)。
  • auth:身份驗(yàn)證密鑰,Web推送的加密描述。

toJSON()

序列化 PushSubscription 對(duì)象,用于存儲(chǔ)和發(fā)送給應(yīng)用服務(wù)器。

subscription.toJSON()

返回如下結(jié)構(gòu):

{endpoint: "https://fcm.googleapis.com/fcm/send/xxx:zzzzzzzzz"expirationTime: nullkeys: {auth: "xxxx-zzzz"p256dh: "BasdfasdfasdfasdffsdafasdfFMRs"} }

unsubscribe()

用于取消訂閱推送服務(wù)。

語(yǔ)法:

?PushSubscription.unsubscribe().then(function(Boolean) { ... });

返回 Promise 的 Boolean。如果 true,則退訂成功。

接口間的關(guān)系

相關(guān)屬性、方法:

Push 相關(guān)事件

Push API 通過下面的 serviceWorker 事件來監(jiān)控并響應(yīng)推送和訂閱更改事件。

onpush

當(dāng) ServiceWorker 收到 Push-Server 推送的消息時(shí),就會(huì)觸發(fā) ServiceWorkerGlobalScope 接口的 onpush 事件。

語(yǔ)法:

ServiceWorkerGlobalScope.onpush = function(PushEvent) { ... } self.addEventListener('push', function(PushEvent) { ... })

通過 PushEvent.data 來獲取 PushMessageData 類型的推送消息中的數(shù)據(jù)。

onpushsubscriptionchange

當(dāng)訂閱信息發(fā)生改變時(shí),會(huì)觸發(fā) ServiceWorkerGlobalScope 接口的 onpushsubscriptionchange 事件,例如:如果推送服務(wù)器設(shè)置了訂閱到期時(shí)間,則可能會(huì)觸發(fā)此事件。(正常訂閱/退訂時(shí)不會(huì)觸發(fā)此事件)

發(fā)生此事件時(shí),通常需要重新訂閱推送服務(wù)器,并把新的訂閱體發(fā)送給應(yīng)用服務(wù)器。

語(yǔ)法:

ServiceWorkerGlobalScope.onpushsubscriptionchange = function() { ... } self.addEventListener('pushsubscriptionchange', function() { ... })

訂閱原理

瀏覽器端訂閱:

瀏覽器端在訂閱 Push Server 時(shí),必須 Notification 是授權(quán)的,否則會(huì)出現(xiàn)授權(quán)窗口,這里的授權(quán)交互和 Notification 的授權(quán)是一樣的。

注意:Notificatino 的授權(quán)狀態(tài)手動(dòng)調(diào)整改變后,訂閱體將失效,需要重新訂閱。

注意:目前大部分國(guó)內(nèi)網(wǎng)絡(luò)環(huán)境無(wú)法訪問 Chrome 的 FCM 推送服務(wù)器,所以在不出海的網(wǎng)絡(luò)環(huán)境下瀏覽器無(wú)法完成訂閱。FireFox 的推送服務(wù)器不存在此問題,所以可以在 FireFox 下測(cè)試此功能。

// 瀏覽器訂閱 navigator.serviceWorker.ready.then(swReg => {swReg.pushManager.subscribe({userVisibleOnly: true,applicationServerKey: urlB64ToUint8Array("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")}).then(pushSubscription => {// 將訂閱信息發(fā)送到你的應(yīng)用服務(wù)器fetch("https://你的應(yīng)用服務(wù)器", {method: "post",body: JSON.stringify(pushSubscription.toJSON())});}).catch(e => {console.log('訂閱失敗', e)console.log('授權(quán)狀態(tài):' + await self.registration.pushManager.permissionState({userVisibleOnly:true}))}); });

關(guān)于推送請(qǐng)求問題,需要使用 VAPID 協(xié)議。

訂閱時(shí)applicationServerKey 使用 VAPID 公鑰作為識(shí)別標(biāo)示,規(guī)范中要求公鑰需要 UInt8 類型,所以訂閱前要進(jìn)行類型轉(zhuǎn)換。

應(yīng)用服務(wù)器端發(fā)送:

應(yīng)用服務(wù)器從數(shù)據(jù)庫(kù)里取出你的訂閱信息,然后根據(jù) Web Push 協(xié)議要求,對(duì)要發(fā)送的消息進(jìn)行拼裝和加密,然后發(fā)送給相應(yīng)的 Push 服務(wù)器,然后 Push 服務(wù)器再根據(jù)訂閱信息中的標(biāo)志發(fā)送給相應(yīng)的終端。

設(shè)備端接收:

瀏覽器端收到推送消息后,會(huì)激活相應(yīng)的 ServiceWorker 線程,并觸發(fā) Push 事件。

例如收到消息后,展示一個(gè) Notification,或者做任何其他的事:

// serviceWorker 環(huán)境下 self.addEventListener("push", function(event) {// 此處可以做任何事console.log("push", event);var data = event.data.json();if (!(self.Notification && self.Notification.permission === "granted")) {return;}self.registration.showNotification(data.title, {body: data.body}); });

詳細(xì)執(zhí)行過程

加密認(rèn)證

瀏覽器訂閱

在 subscribe() 方法中的 applicationServerKey 選項(xiàng)用于推送服務(wù)器鑒別訂閱用戶的應(yīng)用服務(wù),并用確保推送消息發(fā)送給哪個(gè)訂閱用戶。

applicationServerKey 是一對(duì)公私鑰。私鑰應(yīng)用服務(wù)器保存,公鑰交給瀏覽器,瀏覽器訂閱時(shí)將這個(gè)公鑰傳給推送服務(wù)器,這樣推送服務(wù)器可以將你的公鑰和用戶的 PushSubscription 綁定。

你的服務(wù)器發(fā)送

當(dāng)你的服務(wù)器要發(fā)送推送消息時(shí),需要?jiǎng)?chuàng)建一個(gè) Authorization 的 header 頭,Authorization 由規(guī)范要求的加密算法進(jìn)行私鑰加密。推送消息收到消息時(shí),首先取消息請(qǐng)求中 endpoint 對(duì)應(yīng)的公鑰,解碼消息請(qǐng)求中簽名過的 Authorization header 頭,驗(yàn)證簽名是否合法,防止它人偽造身份。通過后,推送服務(wù)器把消息發(fā)送到相應(yīng)的設(shè)備瀏覽器。

注:這里說的 applicationServerKey 就是 VAPID key。

Authorization 的簽名采用 JWT(JSON web token),JWT 是一種向第三方發(fā)送消息的方式,三方收到后,獲取發(fā)送者的公鑰進(jìn)行驗(yàn)證 JWT 的簽名。

JWT 結(jié)構(gòu):

JWT 信息和 JWT 數(shù)據(jù)需要使用 base64 編碼,所以內(nèi)容是公開的。

JWT 信息部分必須包含:

{ "typ": "JWT", "alg": "ES256" }

說明此簽名用的哪種算法。

JWT 數(shù)據(jù)部分,提供有關(guān) JWT 的發(fā)送者、目標(biāo)用戶及有效時(shí)間等信息。

{ "aud": "https://xxx.push-server.com","exp": "1469632224","sub": "mailto:xxx@contact.com" }
  • aud:推送服務(wù)器的地址。
  • exp:簽名過期時(shí)間,單位秒,必須不大于 24 小時(shí)。
  • sub:必須是 URL 或者 郵箱地址。用于推送服務(wù)器聯(lián)系發(fā)送人。

JWT 簽名部分,是取 JWT 信息部分和 JWT 數(shù)據(jù)部分的字符串拼接結(jié)果,中間用.連接,生成未簽名的令牌,然后進(jìn)行簽名生成的。

簽名是基于應(yīng)用服務(wù)器生成的 VAPID 私鑰進(jìn)行加密的,nodejs 可以使用 jws 庫(kù)來簽名:

const jws = require('jws'); const asn1 = require('asn1.js');const header = {typ: 'JWT',alg: 'ES256' };const jwtPayload = {aud: audience,exp: expiration,sub: subject };const jwt = jws.sign({header: header,payload: jwtPayload,privateKey: toPEM(privateKey) });function toPEM(key) {return asn1.define("ECPrivateKey", function() {this.seq().obj(this.key("version").int(),this.key("privateKey").octstr(),this.key("parameters").explicit(0).objid().optional(),this.key("publicKey").explicit(1).bitstr().optional());}).encode({version: 1,privateKey: key,parameters: [1, 2, 840, 10045, 3, 1, 7] // prime256v1},"pem",{label: "EC PRIVATE KEY"}); }

Authorization 對(duì) JWT 簽名的格式要求:

Authorization: 'WebPush <JWT Info>.<JWT Data>.<Signature>'

在簽名的前面加上 WebPush 作為 Authorization 頭的值發(fā)送給推送服務(wù)器。

推送協(xié)議同時(shí)要求Crypto-Key header 頭,用來發(fā)送公鑰,并需要p256ecdsa=前綴,格式:

Crypto-Key: p256ecdsa=<URL Safe Base64 Public Application Server Key>

關(guān)于消息部分的加密

發(fā)送的消息部分,也就是 payload,為了保證安全性,協(xié)議里同樣要求需要加密,且推送服務(wù)器無(wú)法解密,只有瀏覽器才能解密消息數(shù)據(jù)。

在瀏覽器向推送服務(wù)器進(jìn)行訂閱后產(chǎn)生的訂閱體,在這里就用的上了,再看下結(jié)構(gòu):

{endpoint: "https://fcm.googleapis.com/fcm/send/xxx:zzzzzzzzz"expirationTime: nullkeys: {auth: "xxxx-zzzz"p256dh: "BasdfasdfasdfasdffsdafasdfFMRs"} }

結(jié)構(gòu)中的 keys 字段就是瀏覽器端的密鑰信息,由瀏覽器生成。

加密需要 auth、p256dh和payload 三個(gè)值做為輸入進(jìn)行加密,加密過程比較復(fù)雜。

可以看一下,生成的具體要發(fā)送給推送服務(wù)器的字段,下面是 FCM 的請(qǐng)求:

{'hostname': "fcm.googleapis.com",'port': null,'path':"/fcm/send/xxx-xx:APA91bFzxDp-j-xoN_kxqzie3uJS1aSNI5wI4SXL34dLWPFFa3QSZVBOE6eG7b4tb2RIvqUy3d3ww57In2lFsZW5MVsjQRtPFfbKoq9XqqrsTwRZiPDbPcbwZ4vkmv_1lnIHRo5yOxQF",'headers': {'TTL': 3600,"Content-Length": 224,"Content-Type": "application/octet-stream","Content-Encoding": "aesgcm",'Encryption': "salt=lIiVReih7lcahHxS2UhENA","Crypto-Key":"dh=BG9SmS2AixNf9UgRlOr1aEiVQMH5h47cAz0FW-_m9MRiwLqrUUP9DhrbFGXqaHAYh12IyKtvySbnDYNmF3Mh0d0;p256ecdsa=BDTgN25YAAabqE6ANPP49d2EkoLAMxT4xDZxE5BdrCHPyq1zk36LofZ2M3DYosxZzSG7i_26S1ViOGC_rBifW_U",'Authorization':"WebPush eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJhdWQiOiJodHRwczovL2ZjbS5nb29nbGVhcGlzLmNvbSIsImV4cCI6MTU1OTA3ODEwOSwic3ViIjoiaHR0cHM6Ly9kZXZlbG9wZXJzLmdvb2dsZS5jb20vd2ViL2Z1bmRhbWVudGFscy8ifQ.Fa3nW6Lt7cp2dGML71aZItdyIcEabZ4GRVtkQBc3dWavAGH3_xSh0jnT-Cy8vGHJrwwRSRKaOcbt-uniIYt6fA"},'method': "POST" };

VAPID key 生成

密鑰使用 ECDSA(橢圓曲線迪菲-赫爾曼金鑰交換)的 ES256 算法(ECDSA使用 P-256 曲線和 SHA-256 哈希算法的縮寫)。

基于 node 實(shí)現(xiàn):

$ npm install -g web-push $ web-push generate-vapid-keys

基于瀏覽器 JS 實(shí)現(xiàn):

function generateNewKeys() {return crypto.subtle.generateKey({name: 'ECDH', namedCurve: 'P-256'},true, ['deriveBits']).then((keys) => {return cryptoKeyToUrlBase64(keys.publicKey, keys.privateKey);}); }function cryptoKeyToUrlBase64(publicKey, privateKey) {const promises = [];promises.push(crypto.subtle.exportKey('jwk', publicKey).then((jwk) => {const x = base64UrlToUint8Array(jwk.x);const y = base64UrlToUint8Array(jwk.y);const publicKey = new Uint8Array(65);publicKey.set([0x04], 0);publicKey.set(x, 1);publicKey.set(y, 33);return publicKey;}));promises.push(crypto.subtle.exportKey('jwk', privateKey).then((jwk) => {return base64UrlToUint8Array(jwk.d);}));return Promise.all(promises).then((exportedKeys) => {return {public: uint8ArrayToBase64Url(exportedKeys[0]),private: uint8ArrayToBase64Url(exportedKeys[1]),};}); }function base64UrlToUint8Array(base64UrlData) {const padding = '='.repeat((4 - base64UrlData.length % 4) % 4);const base64 = (base64UrlData + padding).replace(/\-/g, '+').replace(/_/g, '/');const rawData = window.atob(base64);const buffer = new Uint8Array(rawData.length);for (let i = 0; i < rawData.length; ++i) {buffer[i] = rawData.charCodeAt(i);}return buffer; }function uint8ArrayToBase64Url(uint8Array, start, end) {start = start || 0;end = end || uint8Array.byteLength;const base64 = window.btoa(String.fromCharCode.apply(null, uint8Array.subarray(start, end)));return base64.replace(/\=/g, '') // eslint-disable-line no-useless-escape.replace(/\+/g, '-').replace(/\//g, '_'); }

應(yīng)用服務(wù)器端實(shí)現(xiàn)

這里用 node 來實(shí)現(xiàn)一下應(yīng)用服務(wù)器向推送服務(wù)器發(fā)送消息。(其他語(yǔ)言環(huán)境可以參考 web-push-libs)

const webpush = require("web-push");const options = {vapidDetails: {subject: "mail@you.com", // 你的聯(lián)系郵箱publicKey: "公鑰",privateKey: "私鑰"},TTL: 60 * 60 // 有效時(shí)間,單位秒 };const subscription = db.getUser("xxx"); // 從數(shù)據(jù)庫(kù)取用戶的訂閱對(duì)象 const payload = {// 要發(fā)送的消息msg: "hellow" };// 發(fā)送消息到推送服務(wù)器 webpush.sendNotification(subscription, payload, options).then(() => {}).catch(err => {// err.statusCode});

基于 web-push-libs 這種封裝好的庫(kù)工具用起來很方便,幾行代碼就可以實(shí)現(xiàn)應(yīng)用服務(wù)器到推送服務(wù)器之間的數(shù)據(jù)請(qǐng)求。

推送服務(wù)器的相應(yīng)狀態(tài)碼

狀態(tài)碼描述
201創(chuàng)建,收到并接受發(fā)送推送消息的請(qǐng)求
429請(qǐng)求過多,意味著應(yīng)用程序服務(wù)器已經(jīng)達(dá)到了推送服務(wù)的速率限制。推送服務(wù)會(huì)包括 Retry-After 標(biāo)頭,來指示在下一個(gè)請(qǐng)求發(fā)出之前等多長(zhǎng)時(shí)間
400無(wú)效的請(qǐng)求,這通常意味著存在無(wú)效的 header 或格式不正確
404未找到,這表示訂閱已過期且無(wú)法使用。在這種情況下,你應(yīng)該刪除 PushSubscription 并等待客戶端重新訂閱用戶
410被移除,訂閱不再有效,應(yīng)從應(yīng)用程序服務(wù)器中刪除。可以通過在 PushSubscription 上調(diào)用 unsubscribe() 來重現(xiàn)
413有效負(fù)載過大,一個(gè)推送服務(wù)支持的最小的有效負(fù)載大小是 4096 bytes (或者 4kb)

常見問題

1. 瀏覽器關(guān)閉可否收到推送?

Android 系統(tǒng):

Android 系統(tǒng)的消息機(jī)制是系統(tǒng)級(jí)的,系統(tǒng)有單獨(dú)的進(jìn)程去監(jiān)聽推送消息,收到消息就會(huì)喚醒對(duì)應(yīng)的應(yīng)用程序來處理這個(gè)推送消息,無(wú)論應(yīng)用是否關(guān)閉。所有應(yīng)用都采用這種處理方式。所以當(dāng)收到瀏覽器的推送消息時(shí),會(huì)喚醒瀏覽器,然后瀏覽器再去激活相應(yīng) 的 ServiceWorker 線程,然后觸發(fā)推送事件。

MAC 系統(tǒng):

MAC 系統(tǒng)下當(dāng)打開應(yīng)用后,默認(rèn)關(guān)閉應(yīng)用實(shí)際上還在后臺(tái)運(yùn)行,可以通過 dock 來查看:

可以看到未完全關(guān)閉的應(yīng)用下面會(huì)有一個(gè)黑點(diǎn)來標(biāo)志,在這種情況下,瀏覽器是可以收到推送消息的。

如果瀏覽器完全關(guān)閉,則當(dāng)在瀏覽器打開后,瀏覽器同樣會(huì)收到通知消息(TTL 有效時(shí)間內(nèi))。

Windows 系統(tǒng):

Windows 系統(tǒng)和 MAC 相似,但判斷瀏覽器是否在后臺(tái)運(yùn)行比較復(fù)雜。

2. 對(duì)于消息推送如何在瀏覽器上調(diào)試查看?

Chrome 環(huán)境下,地址欄輸入chrome://gcm-internals/,并點(diǎn)擊Start Recording按鈕進(jìn)行錄制。

通常來說,主要有兩方面的問題:

  • 發(fā)送消息時(shí)的問題:
    • 授權(quán)問題
    • HTTP 狀態(tài)碼錯(cuò)誤問題
  • 接收消息時(shí)的問題:
    • payload 加密問題
    • 連接問題

如果通過上述工具解決不了問題,可以提交問題到官方:

  • Chrome bugs: https://bugs.chromium.org/p/chromium/issues/list
  • Firefox bugs: https://bugzilla.mozilla.org/home

3. 為什么 Push 比 Web Sockets 好?

Push 是工作在 serviceWorker 線程下的,所以不關(guān)系瀏覽器窗口是否打開。而 Web Sockets 必須保證瀏覽器和網(wǎng)頁(yè)處于打開狀態(tài)才能正常工作。

4. 國(guó)內(nèi)服務(wù)器無(wú)法與 FCM/GCM 推送服務(wù)器通訊,怎么辦?

關(guān)于這一點(diǎn),可以在國(guó)內(nèi)服務(wù)器對(duì)消息通訊的請(qǐng)求上部署代理服務(wù)器,如在 node 環(huán)境下用 web-push 庫(kù)可以這么寫:

webpush.sendNotification(subscription,data,{... options,proxy: '代理地址'} )

或者可以基于三方的推送工具來實(shí)現(xiàn),如:onesignal。


工具

  • 推送加密驗(yàn)證工具:地址
  • Mozilla 推送數(shù)據(jù)加密測(cè)試頁(yè):地址
  • Google Codelab 推送工具:地址
  • JWT 驗(yàn)證:地址

兼容性


博客名稱:王樂平博客

CSDN博客地址:http://blog.csdn.net/lecepin

本作品采用知識(shí)共享署名-非商業(yè)性使用-禁止演繹 4.0 國(guó)際許可協(xié)議進(jìn)行許可。

總結(jié)

以上是生活随笔為你收集整理的PWA(Progressive Web App)入门系列:Push的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。