本程式碼研究室會逐步說明如何建構推播通知伺服器。完成程式碼研究室後,您的伺服器將具有:
- 追蹤推播通知訂閱項目 (也就是說,當用戶端選擇訂閱推播通知時,伺服器會建立新的資料庫記錄,並在用戶端選擇取消訂閱時刪除現有資料庫記錄)
- 向單一用戶端傳送推播通知
- 向所有已訂閱的用戶端傳送推播通知
本程式碼研究室著重於協助您透過實作學習,因此不會過多討論概念。請參閱「推播通知的運作方式」,瞭解推播通知的概念。
本程式碼研究室的用戶端程式碼已完成。您只會在本程式碼研究室中實作伺服器。如要瞭解如何實作推播通知用戶端,請參閱「程式碼研究室:建構推播通知用戶端」。
請查看 push-notifications-server-codelab-complete (原始碼),瞭解完整程式碼。
瀏覽器相容性
本程式碼研究室已知可搭配下列作業系統和瀏覽器組合使用:
- Windows:Chrome、Edge
- macOS:Chrome、Firefox
- Android:Chrome、Firefox
已知本程式碼研究室「無法」搭配使用下列作業系統 (或作業系統和瀏覽器組合):
- macOS:Brave、Edge、Safari
- iOS
應用程式堆疊
- 伺服器是建構在 Express.js 之上。
- web-push Node.js 程式庫會處理所有推播通知邏輯。
- 訂閱資料會使用 lowdb 寫入 JSON 檔案。
您不必使用上述任何技術實作推播通知。我們選擇這些技術,是因為這些技術可提供可靠的程式碼研究室體驗。
設定
取得程式碼的可編輯副本
您在這些操作說明右側看到的程式碼編輯器,在本程式碼研究室中稱為「Glitch UI」。
- 按一下「Remix to Edit」即可編輯專案。
設定驗證方法
您必須先使用驗證金鑰設定伺服器和用戶端,才能使用推播通知。請參閱「簽署網路推播通訊協定要求」一文,瞭解原因。
- 依序點選「Tools」和「Terminal」,開啟 Glitch 終端機。
- 在終端機中執行
npx web-push generate-vapid-keys
。複製私密金鑰和公開金鑰值。 - 開啟
.env
並更新VAPID_PUBLIC_KEY
和VAPID_PRIVATE_KEY
。將VAPID_SUBJECT
設為mailto:test@test.test
。所有這些值都應以雙引號括住。更新後,.env
檔案應如下所示:
VAPID_PUBLIC_KEY="BKiwTvD9HA…"
VAPID_PRIVATE_KEY="4mXG9jBUaU…"
VAPID_SUBJECT="mailto:test@test.test"
- 關閉 Glitch 終端機。
- 開啟
public/index.js
。 - 將
VAPID_PUBLIC_KEY_VALUE_HERE
替換為公開金鑰的值。
管理訂閱項目
您的用戶端會處理大部分的訂閱程序。您的伺服器主要需要執行的作業是儲存新的推播通知訂閱項目,並刪除舊的訂閱項目。這些訂閱項目可讓您日後將訊息推送至用戶端。如要進一步瞭解訂閱程序,請參閱「讓用戶訂閱推播通知」一文。
儲存新的訂閱資訊
- 如要預覽網站,請按下「View App」,然後按下「Fullscreen」。
- 按一下應用程式分頁中的「Register service worker」。您會在狀態方塊中看到類似以下的訊息:
Service worker registered. Scope: https://desert-cactus-sunset.glitch.me/
- 在應用程式分頁中,按一下「訂閱推播」。瀏覽器或作業系統可能會詢問您是否要讓網站傳送推播通知。按一下「允許」(或瀏覽器/作業系統使用的同義詞)。您應該會在狀態方塊中看到類似以下的訊息:
Service worker subscribed to push. Endpoint: https://fcm.googleapis.com/fcm/send/…
- 在 Glitch 使用者介面中按一下「View Source」,即可返回程式碼。
- 依序點選「工具」和「記錄檔」,開啟 Glitch 記錄檔。您應該會看到
/add-subscription
,後面接著一些資料。/add-subscription
是用戶端在想訂閱推播通知時,向用戶端傳送 POST 要求的網址。以下資料是您需要儲存的用戶端訂閱資訊。 - 開啟
server.js
。 - 使用下列程式碼更新
/add-subscription
路徑處理常式邏輯:
app.post('/add-subscription', (request, response) => {
console.log('/add-subscription');
console.log(request.body);
console.log(`Subscribing ${request.body.endpoint}`);
db.get('subscriptions')
.push(request.body)
.write();
response.sendStatus(200);
});
刪除舊的訂閱資訊
- 返回應用程式分頁。
- 按一下「取消訂閱推播通知」。
- 再次查看 Glitch 記錄。您應該會看到
/remove-subscription
和用戶端的訂閱資訊。 - 使用下列程式碼更新
/remove-subscription
路徑處理常式邏輯:
app.post('/remove-subscription', (request, response) => {
console.log('/remove-subscription');
console.log(request.body);
console.log(`Unsubscribing ${request.body.endpoint}`);
db.get('subscriptions')
.remove({endpoint: request.body.endpoint})
.write();
response.sendStatus(200);
});
傳送通知
如傳送推播訊息所述,您的伺服器實際上並不會直接將推播訊息傳送至用戶端。而是依靠推播服務來執行這項操作。您的伺服器基本上只需向使用者所用瀏覽器供應商擁有的網路服務 (推送服務) 提出網路服務要求 (網路推送通訊協定要求),藉此啟動將訊息推送至用戶端的程序。
- 使用下列程式碼更新
/notify-me
路徑處理常式邏輯:
app.post('/notify-me', (request, response) => {
console.log('/notify-me');
console.log(request.body);
console.log(`Notifying ${request.body.endpoint}`);
const subscription =
db.get('subscriptions').find({endpoint: request.body.endpoint}).value();
sendNotifications([subscription]);
response.sendStatus(200);
});
- 使用下列程式碼更新
sendNotifications()
函式:
function sendNotifications(subscriptions) {
// TODO
// Create the notification content.
const notification = JSON.stringify({
title: "Hello, Notifications!",
options: {
body: `ID: ${Math.floor(Math.random() * 100)}`
}
});
// Customize how the push service should attempt to deliver the push message.
// And provide authentication information.
const options = {
TTL: 10000,
vapidDetails: vapidDetails
};
// Send a push message to each client specified in the subscriptions array.
subscriptions.forEach(subscription => {
const endpoint = subscription.endpoint;
const id = endpoint.substr((endpoint.length - 8), endpoint.length);
webpush.sendNotification(subscription, notification, options)
.then(result => {
console.log(`Endpoint ID: ${id}`);
console.log(`Result: ${result.statusCode}`);
})
.catch(error => {
console.log(`Endpoint ID: ${id}`);
console.log(`Error: ${error} `);
});
});
}
- 使用下列程式碼更新
/notify-all
路徑處理常式邏輯:
app.post('/notify-all', (request, response) => {
console.log('/notify-all');
response.sendStatus(200);
console.log('Notifying all subscribers');
const subscriptions =
db.get('subscriptions').cloneDeep().value();
if (subscriptions.length > 0) {
sendNotifications(subscriptions);
response.sendStatus(200);
} else {
response.sendStatus(409);
}
});
- 返回應用程式分頁。
- 依序按一下「取消訂閱推播通知」和「訂閱推播通知」。之所以需要這麼做,是因為如先前所述,Glitch 會在您每次編輯程式碼時重新啟動專案,而專案會在啟動時刪除資料庫。
- 按一下「通知我」。你應該會收到推播通知。標題應為
Hello, Notifications!
,主體應為ID: <ID>
,其中<ID>
為隨機數字。 - 在其他瀏覽器或裝置上開啟應用程式,然後嘗試訂閱推播通知,再按一下「通知所有人」按鈕。所有訂閱的裝置應該都會收到相同的通知 (也就是說,推播通知內文中的 ID 應相同)。
後續步驟
- 如要深入瞭解推播通知的運作方式,請參閱推播通知總覽。
- 請參閱 程式碼研究室:建構推播通知用戶端,瞭解如何建構用戶端,要求通知權限、訂閱裝置以接收推播通知,以及使用服務工作者接收推播訊息,並將訊息顯示為通知。