[譯] 由 Node.js 傳送 Web 推送通知

lsvih發表於2019-03-04

使用 service workers API 可以讓你直接由 Node.js 應用向 Chrome 瀏覽器傳送推送通知。web-push npm 模組可以讓你免去 PubNub 之類的中間商,直接推送訊息。本文將在前端使用原生 JavaScript,在後端使用 Express 框架,通過一個“Hello, World”級別的樣例來帶你瞭解如何進行 web 推送通知。最終的效果如下圖所示。本專案的全部原始碼可在 GitHub 查閱。

[譯] 由 Node.js 傳送 Web 推送通知

鑑權及配置服務端

要設定 web 推送,必須先建立 VAPID keys。VAPID keys 用於識別是誰傳送了推送訊息。npm 的 web-push 模組能夠幫助你生成 VAPID keys,下面我們將安裝 web-push 及其依賴,並使用 web-push generate-vapid-keys 來建立 VAPID keys。

$ npm install express@4.16.3 web-push@3.3.0 body-parser@1.18.2 express-static@1.2.5
+ express@4.16.3
+ web-push@3.3.0
+ body-parser@1.18.2
+ express-static@1.2.5
added 62 packages in 1.42s
$
$ ./node_modules/.bin/web-push generate-vapid-keys
=======================================
Public Key:
BOynOrGhgkj8Bfk4hsFENAQYbnqqLSigUUkCNaBsAmNuH6U9EWywR1JIdxBVQOPDbIuTaj0tVAQbczNLkC5zftw
Private Key:
<OMITTED>
=======================================
$
複製程式碼

如果你需要支援低版本瀏覽器,那麼還要獲取 GCM API key,但在桌面版 Chrome 63 或更高版本中不需要它。

下面建立 index.js 檔案,其中包含你的服務。你需要使用 require() 匯入 web-push 模組,並配置剛才的 VAPID keys。配置相當簡單,將 VAPID keys 存放在 PUBLIC_VAPID_KEYPRIVATE_VAPID_KEY 環境變數中即可。

const webpush = require(`web-push`);
const publicVapidKey = process.env.PUBLIC_VAPID_KEY;
const privateVapidKey = process.env.PRIVATE_VAPID_KEY;
// 此處換成你自己的郵箱
webpush.setVapidDetails(`mailto:val@karpov.io`, publicVapidKey, privateVapidKey);
複製程式碼

下一步,為 Express 應用新增一個名為 /subscribe 的端點。瀏覽器中的 JavaScript 將會傳送一個 body 中包含 PushSubscription 物件的 HTTP 請求。為了用 webpush.sendNotification() 傳送推送通知,你需要獲取 PushSubscription 物件。

const app = express();
app.use(require(`body-parser`).json());
app.post(`/subscribe`, (req, res) => {
  const subscription = req.body;
  res.status(201).json({});
  const payload = JSON.stringify({ title: `test` });
  console.log(subscription);
  webpush.sendNotification(subscription, payload).catch(error => {
    console.error(error.stack);
  });
});
複製程式碼

以上就是服務端需要做的全部配置。你可以在 GitHub 查閱完整程式碼。現在,我們就要建立客戶端 client.js 與一個 service worker —— worker.js 了。

客戶端與 Service Worker

首先,使用 express-static npm 模組對 Express 應用進行配置,為客戶端部署靜態資源,將靜態資源部署在服務的最頂級目錄下。
需要注意的是要在處理 /subscribe 路由之後再呼叫這個 app.use(),否則 Express 將不會根據你的配置處理路由,而是會去查詢 subscribe.html 檔案。

app.use(require(`express-static`)(`./`));
複製程式碼

接著,建立 index.html 檔案,這個檔案將部署為你的應用的入口。檔案中僅有的關鍵之處就是 <script> 標籤,它將載入客戶端 JavaScript 程式碼;其餘部分都無關緊要。

<html>
  <head>
    <title>Push Demo</title>
    <script type="application/javascript" src="/client.js"></script>
  </head>

  <body>
    Service Worker Demo
  </body>
</html>
複製程式碼

現在你的入口做好了。建立一個名為 client.js 的檔案。這個檔案 將告知瀏覽器初始化你的 service worker 並向 /subscribe 傳送 HTTP 請求。由於支援 service workers 的瀏覽器也應該能支援 async 與 await,因此上述示例中使用了 async/await

// 這裡寫死的 public key 要換成你自己的。
const publicVapidKey = `BOynOrGhgkj8Bfk4hsFENAQYbnqqLSigUUkCNaBsAmNuH6U9EWywR1JIdxBVQOPDbIuTaj0tVAQbczNLkC5zftw`;
if (`serviceWorker` in navigator) {
  console.log(`Registering service worker`);
  run().catch(error => console.error(error));
}
async function run() {
  console.log(`Registering service worker`);
  const registration = await navigator.serviceWorker.
    register(`/worker.js`, {scope: `/`});
  console.log(`Registered service worker`);
  console.log(`Registering push`);
  const subscription = await registration.pushManager.
    subscribe({
      userVisibleOnly: true,
      // `urlBase64ToUint8Array()` 函式與以下網址中的描述一致
      // https://www.npmjs.com/package/web-push#using-vapid-key-for-applicationserverkey
      applicationServerKey: urlBase64ToUint8Array(publicVapidKey)
    });
  console.log(`Registered push`);
  console.log(`Sending push`);
  await fetch(`/subscribe`, {
    method: `POST`,
    body: JSON.stringify(subscription),
    headers: {
      `content-type`: `application/json`
    }
  });
  console.log(`Sent push`);
}
複製程式碼

最後,你需要實現 client.js 所載入的 worker.js 檔案。
這個檔案是 service worker 邏輯所在之處。當訂閱者接受到一個推送訊息時,service worker 將收到一個 `push` 事件

console.log(`Loaded service worker!`);
self.addEventListener(`push`, ev => {
  const data = ev.data.json();
  console.log(`Got push`, data);
  self.registration.showNotification(data.title, {
    body: `Hello, World!`,
    icon: `http://mongoosejs.com/docs/images/mongoose5_62x30_transparent.png`
  });
});
複製程式碼

好了!配置正確的環境變數並啟動你的服務:

$ env PUBLIC_VAPID_KEY=`OMITTED` env PRIVATE_VAPID_KEY=`OMITTED` node .
複製程式碼

在 Chrome 中訪問 http://localhost:3000,你應該可以看到下面的推送通知!

[譯] 由 Node.js 傳送 Web 推送通知

這種通知不僅在 Chrome 中可用,在 Firefox 也可以用同樣的程式碼實現。

[譯] 由 Node.js 傳送 Web 推送通知

最後

Web 推送只是 service workers 帶來的諸多好處的其中一種。
通過一個 npm 模組,你就能給大多數現代瀏覽器推送通知。下次你要為你的 web 應用增加推送通知功能的時候,記得用 service workers 哦!


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章