Web Push für interne Dienste
Ich habe über die letzten Monate diverse kleine interne Dienste mit Web Push ausgestattet, um mich über Events auf meinen Servern und auf meinen Macs informieren zu lassen. Das funktioniert fast ausnahmslos fehlerfrei und schnell. Ansonsten habe ich Web Push nur als Spam-Mechanismus auf windigen News-Seiten wahrgenommen.
Es gibt natürlich viele weitere Wege, Push Notifications zu erhalten, von Pushover und ntfy über Telegram, Slack und Matrix. Man kann sich mit seinem eigenen Developer-Zertifikat eine kleine interne App zusammenbauen, die über Firebase und/oder einen eigenen Server via APNS Pushes verschickt. Auch umständlich, und von weiteren externen Diensten abhängig.
Oder eben Web Push, was relativ umständlich und schlecht dokumentiert war, zumindest, als ich zuletzt danach gesehen hatte. Eine Übersicht, wie Codex das bei mir eingerichtet hat:
1. VAPID-Schlüssel erzeugen
Web Push verwendet VAPID (Voluntary Application Server Identification), um den Server zu identifizieren, der Benachrichtigungen verschickt.
Einmalig ein elliptisches P-256-Schlüsselpaar erzeugen. Die meisten Web-Push-Bibliotheken bieten dafür eine Hilfsfunktion. In Go stellt beispielsweise github.com/SherClockHolmes/webpush-go die Funktion webpush.GenerateVAPIDKeys() bereit.
Die Schlüssel sicher speichern:
VAPID_PUBLIC_KEY— wird beim Abonnieren an die Browser weitergegeben.VAPID_PRIVATE_KEY— bleibt ausschließlich auf dem Server.
2. Service Worker registrieren
Ein Service Worker ist eine spezielle Art von Web Worker, der Push-Ereignisse empfangen kann, auch wenn die Website nicht geöffnet ist.
Eine kleine JavaScript-Datei, üblicherweise /sw.js, mit navigator.serviceWorker.register('/sw.js') registrieren.
Der Service Worker benötigt zwei Event-Handler:
push— liest die eingehende Nachricht und zeigt mitself.registration.showNotification()eine Benachrichtigung an.notificationclick— schließt die Benachrichtigung und aktiviert einen vorhandenen Browser-Tab oder öffnet die entsprechende URL mitclients.openWindow().
Der Inhalt einer Benachrichtigung kann aus einem einfachen JSON-Objekt mit title, body und url bestehen.
Das ist schon der ganze Empfangsmechanismus auf Browser-Seite. Der Server übermittelt die Nachricht an den Browseranbieter, der sich darum kümmert, das Gerät zu finden und die Nachricht zuzustellen.
3. Browser abonnieren lassen
In den Einstellungen der Anwendung einen Button „Benachrichtigungen aktivieren“ hinzufügen.
- Mit
Notification.requestPermission()die Berechtigung für Benachrichtigungen anfordern. - Warten, bis der Service Worker bereit ist.
- Mit
registration.pushManager.getSubscription()prüfen, ob bereits ein Abonnement existiert. - Falls nötig, mit
registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: publicKey })eines erstellen. - Das resultierende Abonnement als JSON an das Backend schicken.
publicKey ist der dekodierte öffentliche VAPID-Schlüssel.
Der Browser liefert ein Abonnement mit einer endpoint-URL und zwei Verschlüsselungsschlüsseln: p256dh und auth.
4. Abonnements speichern
SQLite oder eine Textdatei reichen völlig aus.
Eine einfache Tabelle push_subscriptions kann folgende Felder enthalten:
endpoint— eindeutige URL des Push-Dienstes.p256dhundauth— Schlüsselmaterial für die Verschlüsselung.user_id— der authentifizierte Benutzer der Anwendung.
5. Benachrichtigung verschicken
Wenn etwas passiert — ein Dokument wird erstellt, ein Job ist fertig oder neue Inhalte müssen geprüft werden — die entsprechenden Abonnements laden.
Mit einer Web-Push-Bibliothek eine verschlüsselte JSON-Nachricht an jeden Abonnenten schicken und die Anfrage mit den VAPID-Schlüsseln authentifizieren.
In Go übernimmt webpush.SendNotification() das Protokoll, die Verschlüsselung und die VAPID-Authentifizierung.
Der Push-Dienst des Browsers stellt die Nachricht an den registrierten Service Worker zu, der die Benachrichtigung anzeigt.
6. Kleinigkeiten
- HTTPS ist erforderlich für den Produktivbetrieb. Localhost wird für die Entwicklung unterstützt.
- Berechtigungen erst nach einer Benutzeraktion anfordern, nicht automatisch beim Laden der Seite.
- iOS Sweet Solution: Web Push auf iPhones und iPads erfordert eine Web-App, die auf dem Home-Bildschirm installiert ist. Weitere Informationen bei WebKit.