Nutzer für Push-Benachrichtigungen abonnieren

Matt Gaunt

Wenn Sie Push-Benachrichtigungen senden möchten, müssen Sie zuerst die Berechtigung des Nutzers einholen und dann sein Gerät für einen Push-Dienst registrieren. Dazu rufen Sie mit der JavaScript API ein PushSubscription-Objekt ab, das Sie dann an Ihren Server senden.

Die JavaScript API verwaltet diesen Prozess auf einfache Weise. In diesem Leitfaden wird der gesamte Ablauf erläutert, einschließlich der Funktionserkennung, der Anfrage von Berechtigungen und der Verwaltung des Abo-Prozesses.

Feature-Erkennung

Prüfen Sie zuerst, ob der Browser Push-Nachrichten unterstützt. Sie können die Push-Unterstützung mit zwei Prüfungen testen:

  • Suchen Sie im Objekt navigator nach serviceWorker.
  • Suchen Sie im Objekt window nach PushManager.
if (!('serviceWorker' in navigator)) {
  // Service Worker isn't supported on this browser, disable or hide UI.
  return;
}

if (!('PushManager' in window)) {
  // Push isn't supported on this browser, disable or hide UI.
  return;
}

Die Browserunterstützung für Service Worker und Push-Nachrichten nimmt zwar zu, Sie sollten jedoch immer beide Funktionen erkennen und Ihre Anwendung schrittweise verbessern.

Service Worker registrieren

Nach der Featureerkennung wissen Sie, dass Service Worker und Push-Messaging unterstützt werden. Registrieren Sie als Nächstes Ihren Service Worker.

Wenn Sie einen Service Worker registrieren, teilen Sie dem Browser den Speicherort der Service Worker-Datei mit. Die Datei ist eine JavaScript-Datei, aber der Browser gewährt ihr Zugriff auf Service Worker-APIs, einschließlich Push-Messaging. Der Browser führt die Datei in einer Service Worker-Umgebung aus.

Wenn Sie einen Service Worker registrieren möchten, rufen Sie navigator.serviceWorker.register() auf und übergeben Sie den Pfad zu Ihrer Datei. Beispiel:

function registerServiceWorker() {
  return navigator.serviceWorker
    .register('/service-worker.js')
    .then(function (registration) {
      console.log('Service worker successfully registered.');
      return registration;
    })
    .catch(function (err) {
      console.error('Unable to register service worker.', err);
    });
}

Diese Funktion teilt dem Browser den Speicherort der Service Worker-Datei mit. In diesem Fall befindet sich die Service Worker-Datei unter /service-worker.js. Nachdem Sie register() aufgerufen haben, führt der Browser die folgenden Schritte aus:

  1. Laden Sie die Service Worker-Datei herunter.

  2. Führen Sie den JavaScript-Code aus.

  3. Wenn die Datei ohne Fehler ausgeführt wird, wird das von register() zurückgegebene Promise aufgelöst. Wenn Fehler auftreten, wird das Promise abgelehnt.

Hinweis: Wenn register() abgelehnt wird, prüfen Sie Ihr JavaScript in den Chrome-Entwicklertools auf Tippfehler oder Fehler.

Wenn register() aufgelöst wird, wird ein ServiceWorkerRegistration zurückgegeben. Sie verwenden diese Registrierung, um auf die PushManager API zuzugreifen.

Browserkompatibilität der PushManager API

Browser Support

  • Chrome: 42.
  • Edge: 17.
  • Firefox: 44.
  • Safari: 16.

Source

Berechtigung anfordern

Nachdem Sie Ihren Service Worker registriert und die Berechtigung erhalten haben, holen Sie die Berechtigung des Nutzers zum Senden von Push-Benachrichtigungen ein.

Die API zum Einholen der Berechtigung ist einfach. Die API wurde jedoch vor Kurzem geändert, sodass sie jetzt ein Promise zurückgibt, anstatt einen Callback zu akzeptieren. Da Sie nicht feststellen können, welche API-Version der Browser implementiert, müssen Sie beide Versionen implementieren und verarbeiten.

function askPermission() {
  return new Promise(function (resolve, reject) {
    const permissionResult = Notification.requestPermission(function (result) {
      resolve(result);
    });

    if (permissionResult) {
      permissionResult.then(resolve, reject);
    }
  }).then(function (permissionResult) {
    if (permissionResult !== 'granted') {
      throw new Error("We weren't granted permission.");
    }
  });
}

Im vorherigen Code wird durch den Aufruf von Notification.requestPermission() eine Aufforderung für den Nutzer angezeigt:

Berechtigungsaufforderung in Chrome auf Computern und Mobilgeräten

Nachdem der Nutzer mit der Berechtigungsaufforderung interagiert hat, indem er Zulassen oder Blockieren ausgewählt oder die Aufforderung geschlossen hat, erhalten Sie das Ergebnis als String: 'granted', 'default' oder 'denied'.

Im Beispielcode wird das von askPermission() zurückgegebene Promise aufgelöst, wenn die Berechtigung erteilt wurde. Andernfalls wird ein Fehler ausgegeben und das Promise wird abgelehnt.

Behandeln Sie den Grenzfall, in dem der Nutzer auf die Schaltfläche Blockieren klickt. In diesem Fall kann Ihre Web-App den Nutzer nicht noch einmal um Erlaubnis bitten. Der Nutzer muss die Blockierung Ihrer App manuell aufheben, indem er den Berechtigungsstatus in den Einstellungen ändert. Überlegen Sie sich genau, wann und wie Sie um Erlaubnis bitten, denn wenn ein Nutzer auf Blockieren klickt, ist es nicht einfach, diese Entscheidung rückgängig zu machen.

Die meisten Nutzer erteilen die Berechtigung, wenn sie verstehen, warum die App sie anfordert.

In diesem Dokument wird erläutert, wie einige beliebte Websites später in diesem Dokument um Erlaubnis bitten.

Nutzer mit PushManager abonnieren

Nachdem Sie Ihren Service Worker registriert und die Berechtigung erhalten haben, können Sie einen Nutzer abonnieren, indem Sie registration.pushManager.subscribe() aufrufen.

function subscribeUserToPush() {
  return navigator.serviceWorker
    .register('/service-worker.js')
    .then(function (registration) {
      const subscribeOptions = {
        userVisibleOnly: true,
        applicationServerKey: urlBase64ToUint8Array(
          'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
        ),
      };

      return registration.pushManager.subscribe(subscribeOptions);
    })
    .then(function (pushSubscription) {
      console.log(
        'Received PushSubscription: ',
        JSON.stringify(pushSubscription),
      );
      return pushSubscription;
    });
}

Wenn Sie die Methode subscribe() aufrufen, übergeben Sie ein options-Objekt, das aus erforderlichen und optionalen Parametern besteht.

In diesem Abschnitt werden die Optionen beschrieben, die Sie übergeben können.

userVisibleOnly-Optionen

Als Push-Messaging erstmals in Browsern eingeführt wurde, waren sich Entwickler unsicher, ob sie Push-Nachrichten ohne Benachrichtigung senden sollten. Dies wird häufig als „stille Push-Benachrichtigung“ bezeichnet, da der Nutzer nicht weiß, dass im Hintergrund ein Ereignis aufgetreten ist.

Es bestand die Sorge, dass Entwickler den Standort eines Nutzers ohne dessen Wissen kontinuierlich verfolgen könnten.

Um dieses Szenario zu vermeiden und den Autoren der Spezifikation die Möglichkeit zu geben, zu überlegen, wie diese Funktion am besten unterstützt werden kann, wurde die Option userVisibleOnly hinzugefügt. Wenn Sie den Wert true übergeben, wird dem Browser symbolisch mitgeteilt, dass die Web-App jedes Mal eine Benachrichtigung anzeigt, wenn sie eine Push-Nachricht empfängt (also kein stiller Push).

Sie müssen den Wert true übergeben. Wenn Sie den Schlüssel userVisibleOnly nicht angeben oder false übergeben, erhalten Sie den folgenden Fehler:

Chrome currently only supports the Push API for subscriptions that will result
in user-visible messages. You can indicate this by calling
`pushManager.subscribe({userVisibleOnly: true})` instead. See
[https://goo.gl/yqv4Q4](https://goo.gl/yqv4Q4) for more details.

Chrome unterstützt die Push API nur für Abos, die zu für den Nutzer sichtbaren Nachrichten führen. Geben Sie dies durch Aufrufen von pushManager.subscribe({userVisibleOnly: true}) an. Weitere Informationen finden Sie unter https://goo.gl/yqv4Q4.

Anscheinend wird die allgemeine Push-Benachrichtigung ohne Ton in Chrome nicht implementiert. Stattdessen untersuchen die Autoren der Spezifikation eine Budget-API, mit der Web-Apps eine bestimmte Anzahl von stillen Push-Benachrichtigungen basierend auf der Nutzung der Web-App senden können.

Option „applicationServerKey“

In diesem Dokument wurden zuvor Anwendungsserverschlüssel erwähnt. Ein Push-Dienst verwendet Anwendungsserverschlüssel, um die Anwendung zu identifizieren, die einen Nutzer abonniert, und um sicherzustellen, dass dieselbe Anwendung Nachrichten an diesen Nutzer sendet.

Anwendungsserverschlüssel sind ein öffentliches und privates Schlüsselpaar, das für Ihre Anwendung eindeutig ist. Halten Sie den privaten Schlüssel für Ihre Anwendung geheim und geben Sie den öffentlichen Schlüssel frei.

Die Option applicationServerKey, die an den Aufruf subscribe() übergeben wird, ist der öffentliche Schlüssel Ihrer Anwendung. Der Browser übergibt diesen Schlüssel an einen Push-Dienst, wenn der Nutzer abonniert wird. Dadurch kann der Push-Dienst den öffentlichen Schlüssel deiner Anwendung mit dem PushSubscription des Nutzers verknüpfen.

Das folgende Diagramm veranschaulicht diese Schritte.

  1. Laden Sie Ihre Web-App in einem Browser und rufen Sie subscribe() auf. Übergeben Sie dabei den öffentlichen Schlüssel Ihres Anwendungsservers.
  2. Der Browser stellt dann eine Netzwerkanfrage an einen Push-Dienst, der einen Endpunkt generiert, diesen Endpunkt mit dem öffentlichen Schlüssel Ihrer Anwendung verknüpft und den Endpunkt an den Browser zurückgibt.
  3. Der Browser fügt diesen Endpunkt dem PushSubscription hinzu, das vom subscribe()-Promise zurückgegeben wird.

Diagramm, das zeigt, wie der öffentliche Anwendungsserverschlüssel in der Methode „subscribe()“ verwendet wird.

Wenn Sie eine Push-Nachricht senden, erstellen Sie einen Authorization-Header, der Informationen enthält, die mit dem privaten Schlüssel Ihres Anwendungsservers signiert sind. Wenn der Push-Dienst eine Anfrage zum Senden einer Push-Nachricht erhält, validiert er diesen signierten Authorization-Header, indem er den öffentlichen Schlüssel sucht, der mit dem Endpunkt verknüpft ist, der die Anfrage empfängt. Wenn die Signatur gültig ist, weiß der Push-Dienst, dass die Anfrage vom Anwendungsserver mit dem passenden privaten Schlüssel stammt. Dies ist eine Sicherheitsmaßnahme, die verhindert, dass andere Nachrichten an die Nutzer Ihrer Anwendung senden.

Diagramm, das zeigt, wie der private Anwendungsserverschlüssel beim Senden einer Nachricht verwendet wird.

Technisch gesehen ist applicationServerKey optional. Die einfachste Implementierung in Chrome erfordert dies jedoch und andere Browser könnten dies in Zukunft ebenfalls erfordern. In Firefox ist sie optional.

Der Anwendungsserverschlüssel wird in der VAPID-Spezifikation definiert. Wenn Sie Verweise auf Anwendungsserverschlüssel oder VAPID-Schlüssel sehen, denken Sie daran, dass es sich um dieselben Schlüssel handelt.

Anwendungsserverschlüssel erstellen

Sie können einen öffentlichen und einen privaten Satz von Anwendungsserverschlüsseln erstellen, indem Sie die web-push-Befehlszeile verwenden, um Schlüssel wie folgt zu generieren:

    $ npm install -g web-push
    $ web-push generate-vapid-keys

Erstellen Sie diese Schlüssel nur einmal für Ihre Anwendung und achten Sie darauf, dass der private Schlüssel privat bleibt.

Berechtigungen und subscribe()

Der Aufruf von subscribe() hat eine Nebenwirkung. Wenn Ihre Web-App keine Berechtigung zum Anzeigen von Benachrichtigungen hat, wenn Sie subscribe() aufrufen, fordert der Browser die Berechtigungen für Sie an. Das ist nützlich, wenn Ihre Benutzeroberfläche mit diesem Ablauf funktioniert. Wenn Sie jedoch mehr Kontrolle haben möchten (was die meisten Entwickler bevorzugen), verwenden Sie die Notification.requestPermission() API, die weiter oben in diesem Dokument beschrieben wurde.

PushSubscription – Übersicht

Sie rufen subscribe() auf, übergeben Optionen und erhalten ein Promise, das in ein PushSubscription aufgelöst wird. Beispiel:

function subscribeUserToPush() {
  return navigator.serviceWorker
    .register('/service-worker.js')
    .then(function (registration) {
      const subscribeOptions = {
        userVisibleOnly: true,
        applicationServerKey: urlBase64ToUint8Array(
          'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
        ),
      };

      return registration.pushManager.subscribe(subscribeOptions);
    })
    .then(function (pushSubscription) {
      console.log(
        'Received PushSubscription: ',
        JSON.stringify(pushSubscription),
      );
      return pushSubscription;
    });
}

Das PushSubscription-Objekt enthält alle Informationen, die zum Senden von Push-Benachrichtigungen an diesen Nutzer erforderlich sind. Wenn Sie den Inhalt mit JSON.stringify() ausgeben, sehen Sie Folgendes:

    {
      "endpoint": "https://some.pushservice.com/something-unique",
      "keys": {
        "p256dh":
    "BIPUL12DLfytvTajnryr2PRdAgXS3HGKiLqndGcJGabyhHheJYlNGCeXl1dn18gSJ1WAkAPIxr4gK0_dQds4yiI=",
        "auth":"FPssNDTKnInHVndSTdbKFw=="
      }
    }

endpoint ist die URL des Push-Dienstes. Wenn Sie eine Push-Benachrichtigung auslösen möchten, senden Sie eine POST-Anfrage an diese URL.

Das keys-Objekt enthält die Werte, die zum Verschlüsseln von Nachrichtendaten verwendet werden, die mit einer Push-Nachricht gesendet werden. (Die Nachrichtenverschlüsselung wird später in diesem Dokument erläutert.)

Abo an Ihren Server senden

Nachdem Sie ein Push-Abo haben, senden Sie es an Ihren Server. Sie entscheiden, wie Sie sie senden, aber ein Tipp ist, JSON.stringify() zu verwenden, um alle erforderlichen Daten aus dem Aboobjekt zu extrahieren. Alternativ können Sie dasselbe Ergebnis manuell zusammenstellen, zum Beispiel:

const subscriptionObject = {
  endpoint: pushSubscription.endpoint,
  keys: {
    p256dh: pushSubscription.getKeys('p256dh'),
    auth: pushSubscription.getKeys('auth'),
  },
};

// The above is the same output as:

const subscriptionObjectToo = JSON.stringify(pushSubscription);

So senden Sie das Abo von der Webseite:

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 Node.js-Server empfängt diese Anfrage und speichert die Daten zur späteren Verwendung in einer Datenbank.

app.post('/api/save-subscription/', function (req, res) {
  if (!isValidSaveRequest(req, res)) {
    return;
  }

  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.',
          },
        }),
      );
    });
});

Mit den PushSubscription-Details auf Ihrem Server können Sie dem Nutzer jederzeit eine Nachricht senden.

Abo regelmäßig verlängern, um Ablauf zu verhindern

Wenn Sie Push-Benachrichtigungen abonnieren, erhalten Sie oft ein PushSubscription.expirationTime von null. Theoretisch läuft das Abo also nie ab. (Im Gegensatz dazu gibt ein DOMHighResTimeStamp die genaue Ablaufzeit an.) In der Praxis lassen Browser Abos jedoch häufig ablaufen. Das kann beispielsweise passieren, wenn lange Zeit keine Push-Benachrichtigungen empfangen werden oder wenn der Browser erkennt, dass der Nutzer keine App mit Berechtigung zum Senden von Push-Benachrichtigungen verwendet. Eine Möglichkeit, dies zu verhindern, besteht darin, den Nutzer bei jeder empfangenen Benachrichtigung erneut zu abonnieren, wie im folgenden Snippet gezeigt. Dazu müssen Sie Benachrichtigungen so häufig senden, dass der Browser das Abo nicht automatisch ablaufen lässt. Sie sollten die Vor- und Nachteile legitimer Benachrichtigungen sorgfältig gegen die Gefahr abwägen, dass Nutzer nur deshalb mit Spam belästigt werden, um das Ablaufen des Abos zu verhindern. Letztendlich sollten Sie nicht versuchen, die Bemühungen des Browsers zu umgehen, den Nutzer vor längst vergessenen Benachrichtigungsabos zu schützen.

/* In the Service Worker. */

self.addEventListener('push', function(event) {
  console.log('Received a push message', event);

  // Display notification or handle data
  // Example: show a notification
  const title = 'New Notification';
  const body = 'You have new updates!';
  const icon = '/images/icon.png';
  const tag = 'simple-push-demo-notification-tag';

  event.waitUntil(
    self.registration.showNotification(title, {
      body: body,
      icon: icon,
      tag: tag
    })
  );

  // Attempt to resubscribe after receiving a notification
  event.waitUntil(resubscribeToPush());
});

function resubscribeToPush() {
  return self.registration.pushManager.getSubscription()
    .then(function(subscription) {
      if (subscription) {
        return subscription.unsubscribe();
      }
    })
    .then(function() {
      return self.registration.pushManager.subscribe({
        userVisibleOnly: true,
        applicationServerKey: urlBase64ToUint8Array('YOUR_PUBLIC_VAPID_KEY_HERE')
      });
    })
    .then(function(subscription) {
      console.log('Resubscribed to push notifications:', subscription);
      // Optionally, send new subscription details to your server
    })
    .catch(function(error) {
      console.error('Failed to resubscribe:', error);
    });
}

Häufig gestellte Fragen

Hier sind einige häufig gestellte Fragen:

Kann ich den Push-Dienst ändern, den ein Browser verwendet?

Nein, der Browser wählt den Push-Dienst aus. Wie in diesem Dokument im Zusammenhang mit dem subscribe()-Aufruf erläutert, stellt der Browser Netzwerkanfragen an den Push-Dienst, um die Details abzurufen, aus denen sich die PushSubscription zusammensetzt.

Verwenden verschiedene Push-Dienste unterschiedliche APIs?

Alle Push-Dienste erwarten dieselbe API.

Diese gängige API, das Web Push Protocol, beschreibt die Netzwerkanfrage, die Ihre Anwendung stellt, um eine Push-Benachrichtigung auszulösen.

Wenn Sie einen Nutzer auf seinem Desktop-Computer abonnieren, ist er dann auch auf seinem Smartphone abonniert?

Nein. Ein Nutzer muss sich in jedem Browser, in dem er Nachrichten erhalten möchte, für Push-Nachrichten registrieren. Dazu muss der Nutzer auf jedem Gerät die entsprechende Berechtigung erteilen.

Nächste Schritte

Codelabs