使用 NodeJs Express 在 JavaScript 上推送通知

CVO*_*CVO 3 push-notification node.js service-worker web-push

我想从 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);
}
Run Code Online (Sandbox Code Playgroud)

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

var notificationTitle = 'Title';
var notificationOptions = {
    "body": "Some text",
    //"icon": "images/icon.png",
    "vibrate": [200, 100, 200, 100, 200, 100, 400]
}
showNotification(notificationTitle, notificationOptions);
Run Code Online (Sandbox Code Playgroud)

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

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

另外,我在 localhost 中使用 http 来测试它。我真的不知道如果没有 SSL 证书或自动签名证书,这是否可行。

每一个帮助将不胜感激。

CVO*_*CVO 5

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

\n\n

首先需要许多配置步骤:

\n\n
//Installl web push module\nnpm install web-push --save\n\n//Generate VAPID keys by console\ncd ./node_modules/.bin/web-push generate-vapid-keys\n\n//Store VAPID keys on environment\npublicVapidKey: \'generated key\',\nprivateVapidKey: \'generated key\'\nprocess.env.PUBLIC_VAPID_KEY = config.publicVapidKey;\nprocess.env.PRIVATE_VAPID_KEY = config.privateVapidKey;\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

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

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

\n\n
//Send push message\n//TODO: Recover subscription keys from DB\nvar subscription = { \n    endpoint: \'recover from DB\',\n    expirationTime: null,\n    keys: { \n        p256dh: \'recover from DB\',\n        auth: \'recover from DB\' \n    } \n};\nconst payload = JSON.stringify({\n    title: \'Notification Title\',\n    body: \'Notification message\'\n});\nwebpush.setVapidDetails(\n    process.env.DOMAIN, \n    process.env.PUBLIC_VAPID_KEY, \n    process.env.PRIVATE_VAPID_KEY\n);\nwebpush.sendNotification(subscription, payload)\n.catch(function(err) {\n    console.log(err);\n});\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n
//Start subscription\nconst publicVapidKey = \'public key of server\';\nif (window.Notification) {\n    if (Notification.permission != \'granted\') {\n        Notification.requestPermission(() => {\n            if (Notification.permission === \'granted\') {\n                getSubscriptionObject().then(subscribe)\n            }\n        }).catch(function(err) {\n            console.log(err);\n        });\n    }\n}\n\n//Generate subscription object\nfunction getSubscriptionObject() {\n    return navigator.serviceWorker.register(\'/layout/service-worker-push.js\')\n    .then((worker) => {\n        return worker.pushManager.subscribe({\n            userVisibleOnly: true,\n            applicationServerKey: urlBase64ToUint8Array(publicVapidKey)\n        }).catch(function(err) {\n            console.log(err);\n        });\n    }).catch(function(err) {\n        console.log(err);\n    });\n}\n\n//Send subscription to server\nfunction subscribe(subscription) {\n    return fetch(window.location.origin + \'/subscribe\', {\n        method: \'POST\',\n        body: JSON.stringify({\n            subscription: subscription,\n            userId: mv.user_id != undefined ? mv.user_id : \'\'\n        }),\n        headers: {\n            \'content-type\': \'application/json\'\n        }\n    }).catch(function(err) {\n        console.log(err);\n    });\n}\n\n//Decoder base64 to uint8\nfunction urlBase64ToUint8Array(base64String) {\n    const padding = \'=\'.repeat((4 - base64String.length % 4) % 4);\n    const base64 = (base64String + padding)\n        .replace(/-/g, \'+\')\n        .replace(/_/g, \'/\');\n    const rawData = window.atob(base64);\n    const outputArray = new Uint8Array(rawData.length);\n    for (let i = 0; i < rawData.length; ++i) {\n        outputArray[i] = rawData.charCodeAt(i);\n    }\n    return outputArray;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是在客户端发挥作用的 woker(必须在视图中导入)

\n\n
//Event that shows a notification when is received by push\nself.addEventListener(\'push\', event => {\n    const data = event.data.json();\n    self.registration.showNotification(data.title, {\n      body: data.body,\n      icon: "/layout/src/android-chrome-192x192.png"\n    });\n});\n\n//Event on notification click (have problems almost in Chrome)\nself.addEventListener(\'notificationclick\', () => {\n    console.log(\'Notificaci\xc3\xb3n pulsada!\');\n});\n
Run Code Online (Sandbox Code Playgroud)\n\n

以及,嗯,考虑到工人的重要性

\n\n
<script type="text/javascript" src="/layout/service-worker-push.js"></script>\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n