Abonnieren eines Nutzers

Matt Gaunt

Der erste Schritt besteht darin, die Berechtigung vom Nutzer zum Senden von Push-Nachrichten einzuholen. Anschließend können wir ein PushSubscription-Objekt in die Hand nehmen.

Die JavaScript API ist dafür relativ einfach. Gehen wir den logischen Ablauf daher durch.

Funktionserkennung

Zuerst müssen wir überprüfen, ob der aktuelle Browser Push-Nachrichten tatsächlich unterstützt. Mit zwei einfachen Prüfungen können wir prüfen, ob Push unterstützt wird.

  1. Suchen Sie in navigator nach serviceWorker.
  2. Suchen Sie für 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;
}

Auch wenn die Browserunterstützung sowohl für Service Worker als auch für Push-Messaging schnell zunimmt, empfiehlt es sich immer, Featureerkennung für beides und schrittweise Optimierung zu nutzen.

Service Worker registrieren

Durch die Funktion „Detect“ wissen wir, dass sowohl Service Worker als auch Push unterstützt werden. Der nächste Schritt besteht darin, unseren Service Worker zu „registrieren“.

Wenn wir einen Service Worker registrieren, teilen wir dem Browser mit, wo sich die Service Worker-Datei befindet. Bei der Datei handelt es sich weiterhin nur um JavaScript, aber der Browser "gibt ihm Zugriff" auf die Service Worker APIs, einschließlich Push. Genauer gesagt führt der Browser die Datei in einer Service Worker-Umgebung aus.

Um einen Service Worker zu registrieren, rufen Sie navigator.serviceWorker.register() auf und übergeben Sie den Pfad zu unserer Datei. Zum 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 mit, dass wir über eine Service Worker-Datei verfügen und wo sie sich befindet. In diesem Fall befindet sich die Service Worker-Datei unter /service-worker.js. Nach dem Aufruf von register() führt der Browser im Hintergrund die folgenden Schritte aus:

  1. Laden Sie die Service Worker-Datei herunter.

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

  3. Wenn alles korrekt ausgeführt wird und keine Fehler auftreten, wird das von register() zurückgegebene Promise aufgelöst. Wenn es Fehler gibt, lehnt das Versprechen ab.

Falls register() ablehnt, prüfe deinen JavaScript-Code in den Chrome-Entwicklertools noch einmal auf Tippfehler.

Wenn register() aufgelöst wird, wird ein ServiceWorkerRegistration zurückgegeben. Wir verwenden diese Registrierung für den Zugriff auf die PushManager API.

PushManager API-Browserkompatibilität

Unterstützte Browser

  • 42
  • 17
  • 44
  • 16

Quelle

Berechtigung wird angefordert

Der Service Worker wurde registriert und kann den Nutzer abonnieren. Als Nächstes holen wir vom Nutzer die Berechtigung zum Senden von Push-Nachrichten ein.

Die API zum Abrufen von Berechtigungen ist relativ einfach. Der Nachteil ist, dass sich die API kürzlich von einem Callback zu einem Promise geändert hat. Das Problem dabei ist, dass wir nicht wissen können, welche API-Version vom aktuellen Browser implementiert wird. Sie müssen also beide 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 obigen Code ist das wichtige Code-Snippet der Aufruf von Notification.requestPermission(). Bei dieser Methode wird dem Nutzer eine Meldung angezeigt:

Berechtigungsaufforderung in Chrome auf Computern und Mobilgeräten.

Sobald der Nutzer mit der Berechtigungsaufforderung interagiert hat, indem er auf „Zulassen“, „Blockieren“ oder einfach auf das Schließen der Aufforderung geklickt hat, wird das Ergebnis als String zurückgegeben: 'granted', 'default' oder 'denied'.

Im Beispielcode oben wird das von askPermission() zurückgegebene Promise aufgelöst, wenn die Berechtigung gewährt wird. Andernfalls wird ein Fehler ausgegeben, bei dem das Promise abgelehnt wird.

Ein Grenzfall, den Sie handhaben müssen, ist, wenn der Nutzer auf die Schaltfläche „Blockieren“ klickt. In diesem Fall kann Ihre Web-App den Nutzer nicht noch einmal um Erlaubnis bitten. Sie müssen die Blockierung Ihrer App manuell aufheben, indem sie ihren Berechtigungsstatus ändern, der in einem Einstellungsbereich verborgen ist. Überlegen Sie sich gut, wie und wann Sie den Nutzer um seine Berechtigung bitten. Wenn er auf „Sperren“ klickt, ist dies keine einfache Möglichkeit, diese Entscheidung rückgängig zu machen.

Die gute Nachricht ist, dass die meisten Nutzer gerne Berechtigungen erteilen, solange sie wissen, warum sie abgefragt werden.

Wir sehen uns später an, wie einige beliebte Websites um die Berechtigung bitten.

Nutzer mit PushManager abonnieren

Sobald der Service Worker registriert ist und wir die Berechtigung haben, können wir einen Nutzer abonnieren, indem wir 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;
    });
}

Beim Aufrufen der Methode subscribe() wird ein options-Objekt übergeben, das sowohl aus erforderlichen als auch aus optionalen Parametern besteht.

Sehen wir uns alle Optionen an, die übergeben werden können.

„userSichtbarOnly“-Optionen

Als Push-Nachrichten zum ersten Mal in Browsern hinzugefügt wurden, war unsicher, ob Entwickler Push-Nachrichten senden und keine Benachrichtigung anzeigen können sollten. Dies wird im Allgemeinen als „stumm Push“ bezeichnet, da der Nutzer nicht weiß, dass im Hintergrund etwas passiert ist.

Die Entwickler befürchten, dass Entwickler fortlaufend den Standort eines Nutzers verfolgen können, ohne dass der Nutzer das merkt.

Um dieses Szenario zu vermeiden und den Spezifikationsautoren die Möglichkeit zu geben, zu entscheiden, wie diese Funktion am besten unterstützt werden soll, wurde die Option userVisibleOnly hinzugefügt. Die Übergabe des Werts true stellt eine symbolische Vereinbarung mit dem Browser dar, dass die Web-App jedes Mal eine Benachrichtigung anzeigt, wenn eine Push-Benachrichtigung eingeht (d. h. kein stummer Push).

Derzeit müssen Sie den Wert true übergeben. Wenn Sie den Schlüssel userVisibleOnly nicht angeben oder in false nicht übergeben, erhalten Sie die folgende Fehlermeldung:

Chrome unterstützt die Push API derzeit nur für Abos, bei denen für den Nutzer sichtbare Meldungen angezeigt werden. Sie können dies angeben, indem Sie stattdessen pushManager.subscribe({userVisibleOnly: true}) aufrufen. Weitere Informationen finden Sie unter https://goo.gl/yqv4Q4.

Derzeit sieht es so aus, als wird der pauschale stumme Push nie in Chrome implementiert werden. Stattdessen untersuchen Spezifikationsautoren das Konzept einer Budget-API, die Webanwendungen eine bestimmte Anzahl von stummen Push-Nachrichten ermöglicht, basierend auf der Nutzung einer Webanwendung.

„applicationServerKey“-Option

Wir haben im vorherigen Abschnitt kurz auf „Anwendungsserverschlüssel“ eingegangen. "Anwendungsserverschlüssel" werden von einem Push-Dienst verwendet, um die Anwendung zu identifizieren, die einen Nutzer abonniert, und sicherzustellen, dass dieselbe Anwendung diesem Nutzer Nachrichten sendet.

Anwendungsserver sind ein öffentliches und privates Schlüsselpaar, das für Ihre Anwendung eindeutig ist. Der private Schlüssel sollte für Ihre Anwendung geheim gehalten werden und der öffentliche Schlüssel kann frei weitergegeben werden.

Die an den subscribe()-Aufruf übergebene Option applicationServerKey ist der öffentliche Schlüssel der Anwendung. Der Browser übergibt diese beim Abonnieren des Nutzers an einen Push-Dienst, sodass der Push-Dienst den öffentlichen Schlüssel Ihrer Anwendung mit dem PushSubscription des Nutzers verknüpfen kann.

Das folgende Diagramm veranschaulicht diese Schritte.

  1. Ihre Webanwendung wird in einem Browser geladen. Sie rufen subscribe() auf und übergeben den öffentlichen Anwendungsserverschlüssel.
  2. Der Browser stellt dann eine Netzwerkanfrage an einen Push-Dienst, der einen Endpunkt generiert, verknüpft diesen Endpunkt mit dem öffentlichen Schlüssel der Anwendung und gibt den Endpunkt an den Browser zurück.
  3. Der Browser fügt diesen Endpunkt dem PushSubscription hinzu, der über das Promise subscribe() zurückgegeben wird.

Darstellung des öffentlichen Anwendungsserverschlüssels, der in der Subscribe-Methode verwendet wird

Wenn Sie später eine Push-Nachricht senden möchten, müssen Sie einen Authorization-Header erstellen, 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 empfängt, kann er diesen signierten Authorization-Header überprüfen, indem er nach dem ö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 sie vom Anwendungsserver mit dem übereinstimmenden privaten Schlüssel stammen muss. Es handelt sich im Grunde um eine Sicherheitsmaßnahme, die verhindert, dass andere Personen Nachrichten an die Nutzer einer Anwendung senden.

Wie der private Anwendungsserverschlüssel beim Senden einer Nachricht verwendet wird

Technisch gesehen ist die applicationServerKey optional. Für die einfachste Implementierung in Chrome ist sie jedoch erforderlich. Möglicherweise wird sie in Zukunft auch für andere Browser benötigt. In Firefox ist dies optional.

Die Spezifikation, was der Anwendungsserverschlüssel sein sollte, ist die VAPID-Spezifikation. Wenn Sie etwas lesen, das sich auf „Anwendungsserverschlüssel“ oder „VAPID-Schlüssel“ bezieht, denken Sie daran, dass es sich um dasselbe handelt.

Anwendungsserverschlüssel erstellen

Sie können einen öffentlichen und privaten Satz von Anwendungsserverschlüsseln erstellen, indem Sie web-push-codelab.glitch.me aufrufen oder die web-push-Befehlszeile verwenden, um Schlüssel zu generieren. Gehen Sie dazu so vor:

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

Sie müssen diese Schlüssel nur einmal für Ihre Anwendung erstellen. Achten Sie aber darauf, dass Sie den privaten Schlüssel privat halten. (Ja, das habe ich gerade gesagt.)

Berechtigungen und Subscribe()

Das Aufrufen von subscribe() hat einen Nebeneffekt. Wenn Ihre Web-App beim Aufrufen von subscribe() keine Berechtigungen zum Anzeigen von Benachrichtigungen hat, fordert der Browser die Berechtigungen für Sie an. Dies ist nützlich, wenn Ihre UI mit diesem Ablauf funktioniert, Sie aber mehr Kontrolle wünschen (und ich denke, die meisten Entwickler werden dies tun), bleiben Sie an der Notification.requestPermission() API, die wir zuvor verwendet haben.

Was ist ein PushSubscription?

Wir rufen subscribe() auf, übergeben einige Optionen und erhalten im Gegenzug ein Versprechen, das zu einem PushSubscription führt, was zu Code wie diesem führt:

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 Objekt PushSubscription enthält alle erforderlichen Informationen, um Push-Nachrichten an diesen Nutzer zu senden. Wenn Sie den Inhalt mit JSON.stringify() ausdrucken, sehen Sie Folgendes:

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

endpoint ist die URL der Push-Dienste. Um eine Push-Nachricht auszulösen, stellen Sie eine POST-Anfrage an diese URL.

Das keys-Objekt enthält die Werte, mit denen Nachrichtendaten verschlüsselt werden, die mit einer Push-Nachricht gesendet wurden. Darauf gehen wir später in diesem Abschnitt ein.

Abo an Ihren Server senden

Wenn du ein Push-Abo hast, solltest du es an deinen Server senden. Du entscheidest, wie du das machst. Ein kleiner Tipp: Mit JSON.stringify() kannst du alle erforderlichen Daten aus dem Aboobjekt abrufen. Alternativ können Sie dasselbe Ergebnis so manuell zusammensetzen:

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

Das Senden des Abos erfolgt so auf 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 Knotenserver 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 unserem Server können wir dem Nutzer jederzeit eine Nachricht senden.

FAQs

Hier sind einige häufig gestellte Fragen:

Kann ich den von einem Browser verwendeten Push-Dienst ändern?

Nein. Der Push-Dienst wird vom Browser ausgewählt. Wie wir beim subscribe()-Aufruf gesehen haben, sendet der Browser Netzwerkanfragen an den Push-Dienst, um die Details abzurufen, aus denen das PushSubscription besteht.

Jeder Browser verwendet einen anderen Push-Service. Sind nicht unterschiedliche APIs verfügbar?

Alle Push-Dienste erwarten dieselbe API.

Diese gängige API wird Web Push Protocol genannt und beschreibt die Netzwerkanfrage, die Ihre Anwendung stellen muss, um eine Push-Nachricht auszulösen.

Wenn ich einen Nutzer auf seinem Computer abonniere, hat er das Abo dann auch auf seinem Smartphone abonniert?

Leider nicht. Ein Nutzer muss sich in jedem Browser, in dem er Nachrichten empfangen möchte, für Push registrieren. Dabei muss der Nutzer auf jedem Gerät die entsprechende Berechtigung erteilen.

Weitere Informationen

Code-Labs