Start · Sprachen · JavaScript · Referenz · PushSubscription

PushSubscription

Schnittstelle

Stellt ein Push-Abonnement dar: Endpunkt-URL des Push-Dienstes plus öffentlicher Schlüssel und Auth-Geheimnis zum Verschlüsseln von Push-Nachrichten.

seit JavaScript Baseline 2023: Chrome 42+, Edge 17+, Firefox 44+, Kategorie: webapi

Signatur

interface PushSubscription

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, meist null.
  • options (nur lesbar): die Optionen, mit denen abonniert wurde (userVisibleOnly, applicationServerKey).
  • getKey(name): liefert den Schlüssel "p256dh" oder "auth" als ArrayBuffer.
  • toJSON(): gibt ein Objekt { endpoint, expirationTime, keys: { p256dh, auth } } mit Base64url-kodierten Schlüsseln zurück.
  • unsubscribe(): beendet das Abonnement und liefert Promise<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

Typ
PushSubscription
Beschreibung
Eine Instanz kommt aus 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);
Endpunkt: https://fcm.googleapis.com/fcm/send/dXk3...:APA91b...

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();
{ p256dh: "BNcRdreALRFXTkOOUHK1EtK2wtaz5Ry4YfYCA_0QTpQtUbVlUls0VJXg7A8u-Ts1XbjhazAkj7I99e8QcYP7DkM", auth: "tBHItJI5svbpez7KI4CCXg" } 65 16 Läuft ab: null

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();
Abgemeldet: true

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