node.js - 将用户从 OneSignal 迁移到我们自己的数据库,我们从中推送通知

标签 node.js push-notification firebase-cloud-messaging

我正在尝试从 OneSignal 迁移我们的订阅者。我导出了端点、 key (auth 和 P256DH),并在我的服务器上配置了操作系统帐户的 VAPID key 。

当我尝试从操作系统发送通知然后删除操作系统的服务人员并使用我自己的通知时,它发送的通知与我之前通过操作系统发送的通知相同(很奇怪),当我以编程方式删除操作系统的服务人员时(通过控制台)并注册我自己的 service worker,它响应 chrome 的 410 错误(“NotRegistered”)和 Firefox 的 401(“请求未验证缺少的授权 header ”)。
app.js 文件:

let isSubscribed = false;
let swRegistration = null;
let applicationKey = "PUBLIC_VAPID_KEY_HERE";


function urlB64ToUint8Array(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;
}

if ('serviceWorker' in navigator && 'PushManager' in window) {
    console.log('Service Worker and Push is supported');

    navigator.serviceWorker.register('sw.js')
        .then(function (swReg) {
            console.log('service worker registered');

            swRegistration = swReg;

            swRegistration.pushManager.getSubscription()
                .then(function (subscription) {
                    isSubscribed = !(subscription === null);

                    if (isSubscribed) {
                        console.log('User is subscribed');
                    } else {
                        swRegistration.pushManager.subscribe({
                                userVisibleOnly: true,
                                applicationServerKey: urlB64ToUint8Array(applicationKey)
                            })
                            .then(function (subscription) {
                                console.log(subscription);
                                console.log('User is subscribed');

                                saveSubscription(subscription);

                                isSubscribed = true;
                            })
                            .catch(function (err) {
                                console.log('Failed to subscribe user: ', err);
                            })
                    }
                })
        })
        .catch(function (error) {
            console.error('Service Worker Error', error);
        });
} else {
    console.warn('Push messaging is not supported');
}

function saveSubscription(subscription) {
    let xmlHttp = new XMLHttpRequest();
    xmlHttp.open("POST", "/subscribe");
    xmlHttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
    xmlHttp.onreadystatechange = function () {
        if (xmlHttp.readyState != 4) return;
        if (xmlHttp.status != 200 && xmlHttp.status != 304) {
            console.log('HTTP error ' + xmlHttp.status, null);
        } else {
            console.log("User subscribed to server");
        }
    };

    xmlHttp.send(JSON.stringify(subscription));
}

sw.js 文件:

let notificationUrl = '';

self.addEventListener('push', function (event) {
    console.log('Push received: ', event);
    let _data = event.data ? JSON.parse(event.data.text()) : {};
    notificationUrl = _data.url;
    event.waitUntil(
        self.registration.showNotification(_data.title, {
            body: _data.message,
            icon: _data.icon,
            tag: _data.tag
        })
    );
});

self.addEventListener('notificationclick', function (event) {
    event.notification.close();

    event.waitUntil(
        clients.matchAll({
            type: "window"
        })
        .then(function (clientList) {
            if (clients.openWindow) {
                return clients.openWindow(notificationUrl);
            }
        })
    );
});

推送通知的push.js文件:

const express = require('express');
const router = express.Router();
const q = require('q');
const webPush = require('web-push');
const keys = require('./../config/keys');

const mysql = require("mysql");
const pool = mysql.createPool({
  connectionLimit: 10,
  host: 'localhost',
  user: 'root',
  password: 'root',
  database: 'webpush',
  multipleStatements: true,
  dateStrings: true
});

router.post('/push', (req, res) => {
    const payload = {
        title: req.body.title,
        message: req.body.message,
        url: req.body.url,
        ttl: req.body.ttl,
        icon: req.body.icon,
        image: req.body.image,
        badge: req.body.badge,
        tag: req.body.tag
    };

    pool.query('SELECT * FROM subscriber', (err, subscriptions) => {
        if (err) {
            return console.log(err);
            console.error(`Error occurred while getting subscriptions`);
            return res.status(500).json({
                error: 'Technical error occurred'
            });
        }
        if (!subscriptions.length) {
            console.error(`No subscribers found`);
            return res.status(500).json({
                error: 'Subscribers not found'
            });
        }
        let parallelSubscriptionCalls = subscriptions.map(subscription => {
            return new Promise((resolve, reject) => {
                const pushSubscription = {
                    endpoint: subscription.endpoint,
                    keys: {
                        p256dh: subscription.p256dh,
                        auth: subscription.auth
                    }
                };

                const pushPayload = JSON.stringify(payload);
                const pushOptions = {
                    vapidDetails: {
                        subject: 'https://www.mydomainhere.com',
                        privateKey: keys.privateKey,
                        publicKey: keys.publicKey
                    },
                    TTL: payload.ttl,
                    headers: {}
                };
                webPush.sendNotification(pushSubscription, pushPayload, pushOptions)
                .then((value) => {
                    resolve({
                        status: true,
                        endpoint: subscription.endpoint,
                        data: value
                    });
                }).catch((err) => {
                    reject({
                        status: false,
                        endpoint: subscription.endpoint,
                        data: err
                    });
                });
            });
        });
        q.allSettled(parallelSubscriptionCalls).then((pushResults) => {
            console.info(pushResults);
        });
        res.json({
            data: 'Push triggered'
        });
    })
});

module.exports = router;

订阅的 subscribe.js 文件:

const express = require('express');
const router = express.Router();

const mysql = require("mysql");
const pool = mysql.createPool({
  connectionLimit: 10,
  host: 'localhost',
  user: 'root',
  password: 'root',
  database: 'webpush',
  multipleStatements: true,
  dateStrings: true
});


router.post('/subscribe', (req, res) => {
    const endpoint = req.body.endpoint;
    const auth = req.body.keys.auth;
    const p256dh = req.body.keys.p256dh;

    const subscriptionSet = { endpoint, auth, p256dh }

    pool.getConnection((err, connection) => {
        if (err) {
            console.error(`Error occurred while saving subscription. Err: ${err}`);
            return res.status(500).json({
                error: 'Technical error occurred'
            });
        };

        connection.query('INSERT INTO subscriber SET ?', subscriptionSet, (err, subscription) => {
            if (err) {
                console.error(`Error occurred while saving subscription. Err: ${err}`);
                return res.status(500).json({
                    error: 'Technical error occurred'
                });
            }
            res.json({
                data: 'Subscription saved.'
            })
        })
    });
});

module.exports = router;

最佳答案

我正在尝试做同样的事情,您是如何以及在哪里从 onesignal 中导出订阅者身份验证和 P256DH 的?因为在 csv 导出中,onesignal 提供 push_token(端点)而不是 auth 和 P256DH。我在哪里可以获得所有用户身份验证和 P256DH?

关于node.js - 将用户从 OneSignal 迁移到我们自己的数据库,我们从中推送通知,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54638801/

相关文章:

mysql - 如何确认我的 AWS MySQL 连接是安全的?

javascript - 如何为 Node.js 插件创建包装类

android - 如何以及在哪些情况下使用 Notification 类中的 setGroup() 和 setGroupSummary() 方法

javascript - 从 Web 到移动设备的 Firebase 云消息传递

使用 Firebase 的 iOS 推送通知

java - 在没有 Firebase 控制台的情况下向所有设备发送推送通知

javascript - Node.js 阻塞 Bootstrap?

javascript - zombie JS : intermittently crashes when called repeatedly from a for loop

android - 使用 GCM、Urban Airship 发送推送通知

android - 获取推送通知点击事件