使用 NodeJs Express 在 JavaScript 上推送通知

Posted

技术标签:

【中文标题】使用 NodeJs Express 在 JavaScript 上推送通知【英文标题】:Push notifications on JavaScript with NodeJs Express 【发布时间】:2019-10-14 15:04:22 【问题描述】:

我想从 NodeJs 向特定用户发送通知。如果可能的话,这个想法是独立于 firebase 和任何类型的第三方服务器。我找到了很多关于如何构建服务工作者的信息和很多关于显示通知的信息,但是我找不到任何对我有用的关于将推送消息发送到要显示的工作人员的信息。

这里是 service-worker.js

if ('serviceWorker' in navigator) 
    navigator.serviceWorker.register('/layout/service-worker.js')
    .then(function (registration) 
        registration.pushManager.subscribe(
            userVisibleOnly: true
        ).then(function (subscription) 
            isPushEnabled = true;
            console.log("subscription.endpoint: ", subscription.endpoint);
            //Here I will have to store the endpoint on my DB
        );
    ).catch(function (err) 
        console.log(err);
    );


//I think that this could be the listener, but I don't know how to trigger it from the server
this.onpush = function (event) 
    console.log(event.data);

我有这个代码用于显示通知(当我可以发送通知时)

var notificationTitle = 'Title';
var notificationOptions = 
    "body": "Some text",
    //"icon": "images/icon.png",
    "vibrate": [200, 100, 200, 100, 200, 100, 400]

showNotification(notificationTitle, notificationOptions);

这个想法是在“onpush”事件中实现这个代码,我会知道我会收到什么格式。

所以我需要一个方法来向这些方法发送推送,但现在不知道如何去做。我读了一些关于带有 VAPID 键的节点 web-push 模块的内容,但我仍然没有找到发送者喷气机。我有一个 manifest.json,我不知道它是否真的有任何作用(我读到这是 Chrome 导航器所必需的,但不知道,我正在 Chrome、Firefox 和 Edge 中测试所有内容)。

另外,我在 localhost 中使用 http 来测试它。我真的不知道这是否可以在没有 SSL 证书或自动签名证书的情况下工作。

我们将不胜感激。

【问题讨论】:

【参考方案1】:

我找到了解决方案。我不知道是否是最佳的,但它对我有用:

首先需要许多配置步骤:

//Installl web push module
npm install web-push --save

//Generate VAPID keys by console
cd ./node_modules/.bin/web-push generate-vapid-keys

//Store VAPID keys on environment
publicVapidKey: 'generated key',
privateVapidKey: 'generated key'
process.env.PUBLIC_VAPID_KEY = config.publicVapidKey;
process.env.PRIVATE_VAPID_KEY = config.privateVapidKey;

这是从客户端接收订阅并将其存储在 DB 中的 nodejs 控制器代码:

//Subscriptions
app.post('/subscribe', (req, res) => 
    const subscription = req.body.subscription;
    const userId = req.body.userId;
    console.dir(subscription);
    //TODO: Store subscription keys and userId in DB
    webpush.setVapidDetails(
        process.env.DOMAIN, 
        process.env.PUBLIC_VAPID_KEY, 
        process.env.PRIVATE_VAPID_KEY
    );
    res.sendStatus(200);
    const payload = JSON.stringify(
        title: model.lang.pushTitle,
        body: model.lang.pushBody
    );
    webpush.sendNotification(subscription, payload);
);

这是我发现将消息从服​​务器推送到客户端的方法:

//Send push message
//TODO: Recover subscription keys from DB
var subscription =  
    endpoint: 'recover from DB',
    expirationTime: null,
    keys:  
        p256dh: 'recover from DB',
        auth: 'recover from DB' 
     
;
const payload = JSON.stringify(
    title: 'Notification Title',
    body: 'Notification message'
);
webpush.setVapidDetails(
    process.env.DOMAIN, 
    process.env.PUBLIC_VAPID_KEY, 
    process.env.PRIVATE_VAPID_KEY
);
webpush.sendNotification(subscription, payload)
.catch(function(err) 
    console.log(err);
);

这里有客户端视图脚本中的方法来使用必要的数据进行订阅:

//Start subscription
const publicVapidKey = 'public key of server';
if (window.Notification) 
    if (Notification.permission != 'granted') 
        Notification.requestPermission(() => 
            if (Notification.permission === 'granted') 
                getSubscriptionObject().then(subscribe)
            
        ).catch(function(err) 
            console.log(err);
        );
    


//Generate subscription object
function getSubscriptionObject() 
    return navigator.serviceWorker.register('/layout/service-worker-push.js')
    .then((worker) => 
        return worker.pushManager.subscribe(
            userVisibleOnly: true,
            applicationServerKey: urlBase64ToUint8Array(publicVapidKey)
        ).catch(function(err) 
            console.log(err);
        );
    ).catch(function(err) 
        console.log(err);
    );


//Send subscription to server
function subscribe(subscription) 
    return fetch(window.location.origin + '/subscribe', 
        method: 'POST',
        body: JSON.stringify(
            subscription: subscription,
            userId: mv.user_id != undefined ? mv.user_id : ''
        ),
        headers: 
            'content-type': 'application/json'
        
    ).catch(function(err) 
        console.log(err);
    );


//Decoder base64 to uint8
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;

这是在客户端中施展魔法的woker(必须在视图中导入)

//Event that shows a notification when is received by push
self.addEventListener('push', event => 
    const data = event.data.json();
    self.registration.showNotification(data.title, 
      body: data.body,
      icon: "/layout/src/android-chrome-192x192.png"
    );
);

//Event on notification click (have problems almost in Chrome)
self.addEventListener('notificationclick', () => 
    console.log('Notificación pulsada!');
);

还有,工人在视野中的导入

<script type="text/javascript" src="/layout/service-worker-push.js"></script>

注意:我只在 localhost 上测试过,所以不知道是否需要 SSL 证书。

【讨论】:

以上是关于使用 NodeJs Express 在 JavaScript 上推送通知的主要内容,如果未能解决你的问题,请参考以下文章

nodejs 使用express搭建框架总是报错。

httpHeader在nodejs(express)

使用 Express 框架在 Nodejs 中解析 JSON 请求 [重复]

NodeJS 不使用 express 返回 JSONP

如何(重新)在 nodejs/express 中使用 redis 客户端连接?

nodejs/express express.createserver 不是函数