首页 > 解决方案 > 如何通过 Node.js 上的推送通知实现一些复杂的行为

问题描述

我正在试验从 Node.js 应用程序发送的推送通知。遵循一些教程和示例,我现在有了一个可以开始工作的迷你应用程序。

它所做的非常基本,当它被加载到浏览器中时,会触发一个通知,并且用户会看到一条消息弹出。

它基本上由四个文件组成:index.js、index.html、worker.js 和 client.js。

作为第一个实验,我想实现一些稍微复杂的行为。

应用程序应在启动时触发 A 类型的通知(正如它已经在做的那样),然后每 121 分钟触发 B 类型的通知。

这种事情是可能的还是不可能的?

如果有可能,我该怎么做?

作为参考,我在这里放了两个相关文件:

index.js

const express = require('express'),
      webPush = require('web-push'),
      bodyParser = require('body-parser'),
      path = require('path');
const app = express();

app.use(express.static(path.join(__dirname, 'client')));
app.use(bodyParser.json());

const privateVapIdKey = process.env.privVapIdKey,
      publicVapIdKey = process.env.pubVapIdKey;

webPush.setVapidDetails(
    'mailto:myemail@example.com',
    publicVapIdKey,privateVapIdKey);

// Subscribe Route.
app.post('/subscribe',(req,res) => {
    const subscription = req.body; // Get Push Subscription Object.
    res.status(201).json({}); // Send 201. Resource created.

    // Do a lot of useful things ......
    .......
    // Create the PayLoad.
    const payload = JSON.stringify({
        title:'A big title!',
        ........
    });
    // Pass Object to sendNotification.
    webPush.sendNotification(subscription,payload).catch(err => console.error(err));
});

const port = 5003;

const PORT = process.env.PORT || port;
app.listen(PORT, () => console.log(`Listening on ${ PORT }`));

客户端.js

const publicVapIdKey = 'my-secret-3453754...pubVapIdKey';

// Chec for ServiceWorker.
if ('serviceWorker' in navigator) {
    send().catch(err => console.error(err));
}


// Register ServiceWorker, Register Push, Send Push.
async function send() {
    console.log("Registering ServiceWorker.");
    const register = await navigator.serviceWorker.register('/worker.js', {
        scope: "/"
    });
    console.log('ServiceWorker registered.');

    console.log("Registering Push.");
    //register.pushManager.uns
    const subscription = await register.pushManager.subscribe({
        userVisibleOnly: true,
        applicationServerKey: urlBase64ToUint8Array(publicVapIdKey)
    });
    console.log('Push registered.');

    console.log("Sending Push.");
    await fetch('/subscribe', {
        method: 'POST',
        body: JSON.stringify(subscription),
        headers: {
            'content-type': 'application/json'
        }
    });
    console.log('Push sent.');
}


function urlBase64ToUint8Array(base64String) {
    const padding = '='.repeat((4 - base64String.length % 4) % 4);
    const base64 = (base64String + padding)
      .replace(/\-/g, '+')
      .replace(/_/g, '/');

    const rawData = window.atob(base64);
    const outputArray = new Uint8Array(rawData.length);

    for (let i = 0; i < rawData.length; ++i) {
      outputArray[i] = rawData.charCodeAt(i);
    }

    return outputArray;
}

标签: javascriptnode.jspush-notification

解决方案


这是可能的!但我建议您将Admin FCM用于服务器端,它比web-push更新的库和更容易推送通知的方式。

//node.js serverside code 
const FCM = require("firebase-admin");
//fcm-push-notification.json is where all the configurations are
const serviceAccount = require("fcm-push-notification.json");
FCM.initializeApp({
    credential: SERVICE_ACCOUNT,
    databaseURL: DBURL
});
// In your Subscribe Route.
app.post('/subscribe',(req,res) => {
    FCM.messaging()
    .sendToDevice(
    DEVICE_TOKEN,
    {
        data: DATA,
        notification: {
            title: "A big title!",
            body: "HELLO PUSH!"
        }
    }
    )
    .then(res => {
        // do something here
    })
});

这是服务人员

// put firebase-messaging-sw.js service worker
// this is to get notified in the background when the tab is closed on not active 
(global => {
  importScripts("https://www.gstatic.com/firebasejs/4.8.1/firebase-app.js");
  importScripts(
    "https://www.gstatic.com/firebasejs/4.8.1/firebase-messaging.js"
  );
  firebase.initializeApp({
    messagingSenderId: SENDER_ID
  });
  const messaging = firebase.messaging();
  console.log("Service Worker started!");
  messaging.setBackgroundMessageHandler(payload => {
    console.log("Message received In background");
    // Customize notification here
    const notificationOptions = {
      body: "Background Message body.",
      icon: "/firebase-logo.png"
    };
    return global.registration.showNotification("TITLE", notificationOptions);
  });
})(self);

在你的 javascript

//to get notified in forground just do this
import firebase from "firebase";

firebase.initializeApp(FCM_CONF);
let messaging = firebase.messaging();
messaging.usePublicVapidKey(VAPID_KEY);

messaging.onMessage(payload => {
    console.log("Message received from foreground ");
});

最后创建一个 manifest.json

//create manifest.json with content like this
{
  "gcm_sender_id": SENDER_ID
}

并且每 121 分钟触发一次 B 类通知。使用类似later.js 的东西

var later = require('later');
 var schedule = later.parse.text('every 121 min');

 var timer = later.setTimeout(() => {
  // fired every 121 minutes
    FCM.messaging()
    .sendToDevice(
    DEVICE_TOKEN,
    {
        data: DATA,
        notification: {
            title: "A big title!",
            body: "HELLO PUSH!"
        }
    }
    )
 }, schedule);

推荐阅读