[译] 由 Node.js 发送 Web 推送通知

使用 service workers API 可以让你直接由 Node.js 应用向 Chrome 浏览器发送推送通知。web-push npm 模组可以让你免去 PubNub 之类的中间商,直接推送消息。本文将在前端使用原生 JavaScript,在后端使用 Express 框架,通过一个“Hello, World”级别的样例来带你了解如何进行 web 推送通知。最终的效果如下图所示。本项目的全部源码可在 GitHub 查阅。

鉴权及配置服务端

要设置 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,你应该可以看到下面的推送通知!

这种通知不仅在 Chrome 中可用,在 Firefox 也可以用同样的代码实现。

最后

Web 推送只是 service workers 带来的诸多好处的其中一种。 通过一个 npm 模组,你就能给大多数现代浏览器推送通知。下次你要为你的 web 应用增加推送通知功能的时候,记得用 service workers 哦!


掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 AndroidiOS前端后端区块链产品设计人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划官方微博知乎专栏

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值