Push-уведомления на JavaScript с NodeJs Express - PullRequest
0 голосов
/ 14 октября 2019

Я хотел отправлять уведомления определенным пользователям из NodeJs. Идея состоит в том, чтобы быть независимым от firebase и любых сторонних серверов, если это возможно. Я нахожу много информации о том, как создать сервисного работника, и много информации о шоу-уведомлениях, но я не могу найти ничего, что могло бы сработать для меня при отправке push-сообщений рабочему, которые будут показаны.

Вот это 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" qhen я буду знать, какой формат я получу.

Так что мне нужен метод для отправки push-меток этим методам, но не сейчас, как это сделать. Я прочитал кое-что о модуле web-push узла с VAPID-ключами, но я все еще не нашел струю отправителя. У меня есть manifest.json, который я не знаю, действительно ли он что-то делает (я читал, что это необходимо для навигатора Chrome, но не знаю, я тестирую все в Chrome, Firefox и Edge).

Кроме того, я использую http в localhost, чтобы проверить это. Я действительно не знаю, будет ли это работать без сертификата SSL или с автоподписью.

Каждая помощь будет оценена.

1 Ответ

0 голосов
/ 16 октября 2019

Я нашел решение. Я не знаю, является ли это оптимальным, но он работает для меня:

сначала требуется выполнить много шагов настройки:

//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;

вот код контроллера 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;
}

Вот этот вокер (должен быть импортирован в поле зрения), который творит чудеса в клиенте

//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>

примечание: я проверил его только на локальном хосте, поэтому не знаю, требуется ли сертификат SSL.

...