Nachrichten mit Web-Push-Bibliotheken senden

Matt Gaunt

Eines der Probleme bei der Arbeit mit Web Push besteht darin, dass das Auslösen einer Push-Nachricht extrem „knifflig“. Zum Auslösen einer Push-Nachricht muss eine Anwendung eine POST-Anfrage an eine Push-Nachricht senden nach dem Web-Push Protokoll. Um Push-Benachrichtigungen für alle Browser, in denen Sie VAPID verwenden müssen (auch bekannt als Anwendungsserverschlüssel), bei denen ein Header mit einem Wert festgelegt werden muss, Nachrichten an Nutzer senden. Um Daten mit einer Push-Nachricht zu senden, müssen die Daten verschlüsselte und spezifische Header müssen hinzugefügt werden, damit der Browser die Nachricht richtig entschlüsseln kann.

Das Hauptproblem beim Auslösen von Push-Anfragen ist, dass es schwierig ist, das Problem zu lösen. Dies verbessert sich mit der Zeit und mit der Unterstützung weiterer Browser, ist jedoch alles andere als einfach. Für Daher empfehle ich dringend, für die Verschlüsselung, Formatierung und die Ihre Push-Nachricht auslöst.

Wenn Sie wirklich mehr darüber erfahren möchten, was Bibliotheken tun, gehen wir darauf ein. im nächsten Abschnitt. Zunächst sehen wir uns die Verwaltung von Abos und die Verwendung eines vorhandene Web-Push-Bibliothek für die Push-Anfragen.

In diesem Abschnitt verwenden wir den web-push Node Bibliothek. Andere Sprachen haben zwar Unterschiede, werden sie nicht allzu sehr unterschiedlich sein. Wir sehen uns Node an, da es sich um JavaScript handelt und der für die Leser leicht zugänglich sind.

Wir führen die folgenden Schritte aus:

  1. Senden Sie ein Abo an unser Backend und speichern Sie es.
  2. Gespeicherte Abos abrufen und eine Push-Nachricht auslösen.

Abos werden gespeichert

Das Speichern und Abfragen von PushSubscription-Objekten aus einer Datenbank hängt davon ab, Ihre serverseitige Sprache und Datenbankauswahl, aber es könnte nützlich sein, ein Beispiel dafür, wie das möglich ist.

Auf der Demo-Webseite wird PushSubscription mit einer einfachen POST-Anfrage an unser Back-End gesendet:

function sendSubscriptionToBackEnd(subscription) {
  return fetch('/api/save-subscription/', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(subscription),
  })
    .then(function (response) {
      if (!response.ok) {
        throw new Error('Bad status code from server.');
      }

      return response.json();
    })
    .then(function (responseData) {
      if (!(responseData.data && responseData.data.success)) {
        throw new Error('Bad response from server.');
      }
    });
}

Der Express-Server in unserer Demo verfügt über einen passenden Anfrage-Listener für den /api/save-subscription/-Endpunkt:

app.post('/api/save-subscription/', function (req, res) {

Auf diesem Weg validieren wir das Abo, um sicherzustellen, dass die Anfrage in Ordnung ist und nicht voll Mülleimer:

const isValidSaveRequest = (req, res) => {
  // Check the request body has at least an endpoint.
  if (!req.body || !req.body.endpoint) {
    // Not a valid subscription.
    res.status(400);
    res.setHeader('Content-Type', 'application/json');
    res.send(
      JSON.stringify({
        error: {
          id: 'no-endpoint',
          message: 'Subscription must have an endpoint.',
        },
      }),
    );
    return false;
  }
  return true;
};

Wenn das Abonnement gültig ist, müssen wir es speichern und eine entsprechende JSON-Antwort:

return saveSubscriptionToDatabase(req.body)
  .then(function (subscriptionId) {
    res.setHeader('Content-Type', 'application/json');
    res.send(JSON.stringify({data: {success: true}}));
  })
  .catch(function (err) {
    res.status(500);
    res.setHeader('Content-Type', 'application/json');
    res.send(
      JSON.stringify({
        error: {
          id: 'unable-to-save-subscription',
          message:
            'The subscription was received but we were unable to save it to our database.',
        },
      }),
    );
  });

In dieser Demo wird nedb zum Speichern der Abos verwendet. eine einfache, dateibasierte Datenbank. Sie können aber auch jede beliebige Datenbank verwenden. Wir verwenden sie nur als erfordert keine Einrichtung. Für die Produktion solltest du eine zuverlässigere Technologie verwenden. (Ich neige dazu, bleiben Sie bei der guten alten MySQL-Datenbank.)

function saveSubscriptionToDatabase(subscription) {
  return new Promise(function (resolve, reject) {
    db.insert(subscription, function (err, newDoc) {
      if (err) {
        reject(err);
        return;
      }

      resolve(newDoc._id);
    });
  });
}

Push-Nachrichten senden

Beim Senden einer Push-Nachricht brauchen wir letztendlich ein Ereignis, das den Prozess der eine Nachricht an Nutzende zu senden. Häufig wird eine Administratorseite erstellt, die Push-Nachricht zu konfigurieren und auszulösen. Sie können aber auch ein Programm erstellen, das lokal oder Anderer Ansatz, der es ermöglicht, auf die Liste von PushSubscriptions zuzugreifen und den Code auszuführen, die Push-Nachricht auslösen.

Unsere Demo hat eine „Admin-Like“ Seite, mit der Sie eine Push-Anfrage auslösen können. Da es sich nur um eine Demo handelt, öffentlichen Seite zu sehen sind.

Ich werde die einzelnen Schritte zur Funktion der Demo durchgehen. Das sind Babys damit alle dem Projekt folgen können, auch Neulinge bei Node.

Als wir über das Abonnieren eines Nutzers sprachen, haben wir darüber gesprochen, wie man ein applicationServerKey zum subscribe() Optionen. Am Back-End benötigen wir diesen privaten Schlüssel.

In der Demo werden diese Werte so zu unserer Node-App hinzugefügt (langweiliger Code, den ich kenne, aber möchte nur dass es keine Magie gibt):

const vapidKeys = {
  publicKey:
    'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
  privateKey: 'UUxI4O8-FbRouAevSmBQ6o18hgE4nSG3qwvJTfKc-ls',
};

Als Nächstes müssen Sie das Modul web-push für unseren Knotenserver installieren:

npm install web-push --save

Im Node-Skript benötigen wir dann das Modul web-push. etwa so:

const webpush = require('web-push');

Jetzt können wir mit der Verwendung des Moduls web-push beginnen. Zuerst müssen wir dem web-push-Modul unsere Anwendungsserverschlüssel. (Denken Sie daran, sie werden auch als VAPID-Schlüssel bezeichnet, der Spezifikation.)

const vapidKeys = {
  publicKey:
    'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
  privateKey: 'UUxI4O8-FbRouAevSmBQ6o18hgE4nSG3qwvJTfKc-ls',
};

webpush.setVapidDetails(
  'mailto:web-push-book@gauntface.com',
  vapidKeys.publicKey,
  vapidKeys.privateKey,
);

Beachten Sie, dass auch ein "mailto:"- . Diese Zeichenfolge muss entweder eine URL oder ein mailto E-Mail-Adresse. Diese Information wird im Rahmen von die Anfrage zum Auslösen einer Push-Anfrage. Dies geschieht, damit ein Web-Push-Dienst um den Absender zu kontaktieren, hat er einige Informationen, die ihm dabei helfen können.

Damit ist das Modul web-push einsatzbereit. Der nächste Schritt besteht darin, eine Push-Nachricht auszulösen.

In der Demo wird das vorgegebene Admin-Steuerfeld verwendet, um Push-Nachrichten auszulösen.

Screenshot der Seite „Verwaltung“

Durch Klicken auf "Push-Nachricht auslösen" wird eine POST-Anfrage an /api/trigger-push-msg/ gesendet, Dies ist das Signal für unser Back-End, dass Push-Nachrichten gesendet werden sollen. Also erstellen wir die Route in Express für diesen Endpunkt:

app.post('/api/trigger-push-msg/', function (req, res) {

Wenn diese Anfrage eingeht, nehmen wir die Abos aus der Datenbank lösen wir eine Push-Nachricht aus.

return getSubscriptionsFromDatabase().then(function (subscriptions) {
  let promiseChain = Promise.resolve();

  for (let i = 0; i < subscriptions.length; i++) {
    const subscription = subscriptions[i];
    promiseChain = promiseChain.then(() => {
      return triggerPushMsg(subscription, dataToSend);
    });
  }

  return promiseChain;
});

Die Funktion triggerPushMsg() kann dann mithilfe der Web-Push-Bibliothek eine Nachricht an den Abo.

const triggerPushMsg = function (subscription, dataToSend) {
  return webpush.sendNotification(subscription, dataToSend).catch((err) => {
    if (err.statusCode === 404 || err.statusCode === 410) {
      console.log('Subscription has expired or is no longer valid: ', err);
      return deleteSubscriptionFromDatabase(subscription._id);
    } else {
      throw err;
    }
  });
};

Beim Aufruf von webpush.sendNotification() wird ein Promise zurückgegeben. Wenn der Parameter erfolgreich versendet wurde, wird das Promise aufgelöst und es gibt müssen wir nichts weiter tun. Wenn das Versprechen abgelehnt wird, musst du das da Sie darüber informiert werden, ob PushSubscription immer noch gültig oder nicht.

Um die Art des Fehlers von einem Push-Dienst zu bestimmen, sehen Sie sich am besten den Statuscode an. Fehler Die Botschaften unterscheiden sich zwischen den Push-Diensten und einige sind hilfreicher als andere.

In diesem Beispiel wird nach den Statuscodes 404 und 410 gesucht. Dies sind die HTTP-Statuscodes für „Nicht gefunden“ und „Gelöscht“. Wenn wir eine solche Meldung erhalten, ist das Abo abgelaufen. oder nicht mehr gültig ist. In diesen Szenarien müssen wir die Abos aus unserer Datenbank entfernen.

Für einen anderen Fehler verwenden wir nur throw err, wodurch das Versprechen zurückgegeben wird, das vom triggerPushMsg() abgelehnt.

Einige der anderen Statuscodes werden im nächsten Abschnitt behandelt, wenn wir uns die Web-Push-Funktion ansehen. -Protokolls genauer an.

Nach dem Durchlauf der Abos müssen wir eine JSON-Antwort zurückgeben.

.then(() => {
res.setHeader('Content-Type', 'application/json');
    res.send(JSON.stringify({ data: { success: true } }));
})
.catch(function(err) {
res.status(500);
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({
    error: {
    id: 'unable-to-send-messages',
    message: `We were unable to send messages to all subscriptions : ` +
        `'${err.message}'`
    }
}));
});

Wir haben die wichtigsten Schritte für die Implementierung besprochen:

  1. Erstellen Sie eine API, um Abos von unserer Webseite an unser Backend zu senden um sie in einer Datenbank zu speichern.
  2. Erstellen Sie eine API, um das Senden von Push-Nachrichten auszulösen (in diesem Fall eine API, die über das vorgegebene Admin-Steuerfeld aufgerufen wird).
  3. Rufen Sie alle Abos aus unserem Backend ab. und senden mit einer der Web-Push-Aktionen Bibliotheken.

Unabhängig von Ihrem Back-End (Node, PHP, Python usw.) können die Schritte zur Implementierung von Push ausgeführt werden. dass sie identisch sind.

Als Nächstes fragen wir uns, was genau diese Web-Push-Bibliotheken für uns bewirken.

Weitere Informationen

Code labs