Signatur
Beschreibung
Das Interface PushSubscription der Push API steht für ein einzelnes Push-Abonnement eines Service Workers. Es enthält die endpoint-URL des Push-Dienstes des Browsers (z. B. FCM, Mozilla Autopush, Apple Push Service) sowie die kryptografischen Schlüssel (p256dh und auth). Damit kann der Anwendungsserver Nachrichten nach RFC 8291 (Message Encryption for Web Push) verschlüsseln und an genau diesen Client senden.
Du erzeugst keine Instanz direkt, sondern bekommst sie über registration.pushManager.subscribe() oder registration.pushManager.getSubscription(). Normalerweise wird das Abonnement per toJSON() serialisiert, an den eigenen Server geschickt und dort gespeichert. Der Server nutzt diese Daten dann zusammen mit seinem VAPID-Schlüsselpaar, um Nachrichten zu versenden (z. B. mit der Node.js-Bibliothek web-push).
Wichtige Mitglieder:
endpoint(nur lesbar,string): die URL, an die der Server Push-Nachrichten per POST schickt.expirationTime(nur lesbar,number | null): Ablaufzeitpunkt als DOMHighResTimeStamp, meistnull.options(nur lesbar): die Optionen, mit denen abonniert wurde (userVisibleOnly,applicationServerKey).getKey(name): liefert den Schlüssel"p256dh"oder"auth"alsArrayBuffer.toJSON(): gibt ein Objekt{ endpoint, expirationTime, keys: { p256dh, auth } }mit Base64url-kodierten Schlüsseln zurück.unsubscribe(): beendet das Abonnement und liefertPromise<boolean>.
Die Push API geht nur in einem sicheren Kontext (HTTPS oder localhost), braucht einen registrierten Service Worker und die Benachrichtigungs-Berechtigung des Nutzers.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $name (getKey) Pflicht | "p256dh" | "auth" | Für getKey(): "p256dh" ist der öffentliche ECDH-Schlüssel (P-256) des Clients, "auth" das 16-Byte-Authentifizierungsgeheimnis. |
Rückgabewert
PushManager.subscribe() bzw. PushManager.getSubscription() (bei getSubscription() ist das Ergebnis null, wenn kein Abonnement existiert). getKey() gibt ArrayBuffer | null zurück, toJSON() ein einfaches Objekt und unsubscribe() ein Promise<boolean>.Beispiele
Abonnement anlegen und an den Server senden
// Öffentlicher VAPID-Schlüssel des Servers (Base64url)
const VAPID_PUBLIC_KEY = 'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U';
const urlBase64ToUint8Array = (base64) => {
const padding = '='.repeat((4 - (base64.length % 4)) % 4);
const raw = atob((base64 + padding).replace(/-/g, '+').replace(/_/g, '/'));
return Uint8Array.from(raw, (c) => c.charCodeAt(0));
};
const subscribeToPush = async () => {
const registration = await navigator.serviceWorker.register('/sw.js');
const permission = await Notification.requestPermission();
if (permission !== 'granted') return null;
const subscription = await registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(VAPID_PUBLIC_KEY)
});
await fetch('/api/push/subscribe', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(subscription) // ruft intern toJSON() auf
});
console.log('Endpunkt:', subscription.endpoint);
return subscription;
};
// Aufruf nur nach einer Nutzeraktion, z. B. einem Klick
document.querySelector('#push-btn').addEventListener('click', subscribeToPush);
Vorhandenes Abonnement auslesen: toJSON() und getKey()
const showSubscription = async () => {
const registration = await navigator.serviceWorker.ready;
const subscription = await registration.pushManager.getSubscription();
if (!subscription) {
console.log('Kein Abonnement vorhanden');
return;
}
const json = subscription.toJSON();
console.log(json.keys);
// Rohschlüssel als ArrayBuffer
const p256dh = subscription.getKey('p256dh');
const auth = subscription.getKey('auth');
console.log(p256dh.byteLength, auth.byteLength);
console.log('Läuft ab:', subscription.expirationTime);
};
showSubscription();
Abmelden (unsubscribe) und Server informieren
const unsubscribeFromPush = async () => {
const registration = await navigator.serviceWorker.ready;
const subscription = await registration.pushManager.getSubscription();
if (!subscription) return false;
const { endpoint } = subscription;
const ok = await subscription.unsubscribe();
if (ok) {
await fetch('/api/push/unsubscribe', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ endpoint })
});
}
console.log('Abgemeldet:', ok);
return ok;
};
unsubscribeFromPush();
Serverseitig senden (Node.js mit web-push)
// npm install web-push
import webpush from 'web-push';
webpush.setVapidDetails(
'mailto:admin@example.com',
process.env.VAPID_PUBLIC_KEY,
process.env.VAPID_PRIVATE_KEY
);
// subscription = gespeichertes toJSON()-Objekt aus der Datenbank
const sendNotification = async (subscription, payload) => {
try {
await webpush.sendNotification(subscription, JSON.stringify(payload));
} catch (err) {
// 404/410: Abonnement ungültig, aus der Datenbank löschen
if (err.statusCode === 404 || err.statusCode === 410) {
console.log('Abonnement abgelaufen:', subscription.endpoint);
} else {
throw err;
}
}
};