簡體   English   中英

將用戶從 OneSignal 遷移到我們自己的數據庫,我們從中推送通知

[英]Migrating users from OneSignal to our own database that we push notifications from

我正在嘗試從 OneSignal 遷移我們的訂閱者。 我導出了端點、密鑰(auth 和 P256DH),並在服務器上配置了操作系統帳戶的 VAPID 密鑰。

當我嘗試從 OS 發送通知然后刪除 OS 的 service worker 並使用我自己的通知時,它發送的通知與我之前通過 OS 發送的通知相同(很奇怪),當我以編程方式刪除 OS 的 service worker 時(通過控制台)並注冊我自己的服務工作者,它響應來自 chrome(“NotRegistered”)的 410 錯誤和來自 Firefox 的 401(“請求未驗證缺少的授權標頭”)。
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?

根據我的理解,除非訂閱者回來訪問您的域,否則您無法重新注冊 Service Worker。 但是,Service Worker 每天都會更新,因此您可以做的是編輯現有的 One 信號 Service Worker 文件——刪除它們的內容並添加您自己的代碼或導入腳本。 確保不要更改文件位置或重命名一個信號服務工作者文件,它需要是相同的文件名。 這將算作“更新”,瀏覽器應自動替換內容,無需用戶采取任何行動。 如果有兩個 OneSignal 服務工作者文件,則更改兩者。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM