Start · Sprachen · JavaScript · Referenz · ServiceWorkerGlobalScope: pushsubscriptionchange

ServiceWorkerGlobalScope: pushsubscriptionchange

Ereignis

Wird im Service Worker ausgelöst, wenn sich das Push-Abonnement ohne Zutun der Anwendung ändert, z. B. weil es abläuft, erneuert oder vom Push-Dienst widerrufen wird.

seit JavaScript Eingeschränkte Unterstützung: Firefox (Desktop/And Kategorie: webapi

Signatur

self.addEventListener("pushsubscriptionchange", handler)

Beschreibung

Das Event pushsubscriptionchange wird am ServiceWorkerGlobalScope ausgelöst, wenn sich ein Push-Abonnement ändert, ohne dass die Anwendung das veranlasst hat. Typische Gründe sind ein abgelaufenes Abonnement (expirationTime erreicht), eine vom Push-Dienst erneuerte Verbindung oder ein vom Browser widerrufenes Abonnement. Ohne Reaktion darauf sendet der Server Nachrichten an einen Endpunkt, der nicht mehr gültig ist, und Push-Benachrichtigungen kommen nicht mehr an.

Einen Handler registrierst du per self.addEventListener("pushsubscriptionchange", handler) oder über die Eigenschaft self.onpushsubscriptionchange. Das Event-Objekt ist laut Spezifikation ein PushSubscriptionChangeEvent (erweitert ExtendableEvent) mit den Eigenschaften oldSubscription und newSubscription. Beide können null sein, z. B. wenn der Browser das alte Abonnement verworfen und noch kein neues angelegt hat.

Meist sieht der Ablauf so aus: Du legst über self.registration.pushManager.subscribe() ein neues Abonnement an, schickst es an deinen Anwendungsserver und entfernst dort den alten Endpunkt. Diese asynchrone Arbeit muss in event.waitUntil() eingeschlossen werden, sonst kann der Browser den Service Worker vorher beenden.

Parameter

Name Typ Default Beschreibung
$type Pflicht string Der Event-Name "pushsubscriptionchange".
$handler Pflicht (event: PushSubscriptionChangeEvent) => void Callback, der das Event-Objekt erhält. Wichtige Mitglieder: event.oldSubscription (PushSubscription | null), event.newSubscription (PushSubscription | null) und event.waitUntil(promise).
$options boolean | AddEventListenerOptions false Optionale Listener-Optionen wie bei addEventListener (z. B. { once: true }).

Rückgabewert

Typ
void
Beschreibung
addEventListener hat keinen Rückgabewert. Wenn du Arbeit in event.waitUntil() übergibst, bleibt der Service Worker aktiv, bis das Promise erfüllt oder abgelehnt ist.

Beispiele

Neu abonnieren und den Server informieren (addEventListener)

// sw.js
const VAPID_PUBLIC_KEY = 'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U';

// Base64url-String in ein Uint8Array umwandeln
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));
};

self.addEventListener('pushsubscriptionchange', (event) => {
  const resubscribe = async () => {
    // Neues Abonnement verwenden, wenn der Browser schon eines angelegt hat
    const subscription = event.newSubscription ??
      await self.registration.pushManager.subscribe({
        userVisibleOnly: true,
        applicationServerKey:
          event.oldSubscription?.options?.applicationServerKey ??
          urlBase64ToUint8Array(VAPID_PUBLIC_KEY)
      });

    await fetch('/api/push/subscription', {
      method: 'PUT',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        oldEndpoint: event.oldSubscription?.endpoint ?? null,
        subscription: subscription.toJSON()
      })
    });
    console.log('Push-Abonnement erneuert:', subscription.endpoint);
  };

  event.waitUntil(resubscribe());
});
Push-Abonnement erneuert: https://updates.push.services.mozilla.com/wpush/v2/gAAAA...

Handler über die on-Property setzen

// sw.js
self.onpushsubscriptionchange = (event) => {
  event.waitUntil(
    fetch('/api/push/unsubscribe', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ endpoint: event.oldSubscription?.endpoint ?? null })
    }).then(() => console.log('Alter Endpunkt wurde auf dem Server entfernt'))
  );
};
Alter Endpunkt wurde auf dem Server entfernt

Listener wieder entfernen

// sw.js
const onSubscriptionChange = (event) => {
  console.log('Änderung erkannt, altes Abo:', event.oldSubscription?.endpoint);
};

self.addEventListener('pushsubscriptionchange', onSubscriptionChange);

// Später, z. B. nach einer Konfigurationsänderung:
self.removeEventListener('pushsubscriptionchange', onSubscriptionChange);
console.log('Listener entfernt');
Listener entfernt

Fallback ohne Event: Abonnement beim Seitenstart prüfen

// main.js – für Browser, die das Event nicht auslösen
const syncSubscription = async () => {
  const registration = await navigator.serviceWorker.ready;
  const subscription = await registration.pushManager.getSubscription();
  if (!subscription) {
    console.log('Kein Abonnement mehr – Nutzer neu abonnieren');
    return;
  }
  await fetch('/api/push/subscription', {
    method: 'PUT',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ subscription: subscription.toJSON() })
  });
  console.log('Abonnement mit Server abgeglichen');
};

syncSubscription();
Abonnement mit Server abgeglichen

// Wichtig · Fallstricke

  • Browser-Unterstützung: Nur Firefox löst das Event zuverlässig aus. Chromium-Browser und Safari lösen es praktisch nicht aus. Verlass dich deshalb nicht allein darauf: Prüfe das Abonnement zusätzlich bei jedem Seitenaufruf mit pushManager.getSubscription() und gleiche es mit dem Server ab.
  • oldSubscription/newSubscription können null sein oder in älteren Implementierungen fehlen. Nutze darum optionale Verkettung (?.) und halte den VAPID-Schlüssel als Rückfallwert bereit.
  • Kein Nutzerkontext: Das Event kann auftreten, während keine Seite offen ist. Ist die Benachrichtigungs-Berechtigung widerrufen worden, schlägt subscribe() fehl. Fang den Fehler ab und entferne den Endpunkt auf dem Server.
  • waitUntil() nicht vergessen: Ohne diesen Aufruf kann der Browser den Service Worker beenden, bevor fetch fertig ist.
  • Listener müssen synchron bei der ersten Auswertung des Service-Worker-Skripts registriert werden, nicht erst in einem Promise oder setTimeout.
  • Sicherheit: Der Server-Endpunkt, der Abonnements aktualisiert, sollte die Zuordnung zum Nutzer prüfen, z. B. über Cookies oder ein Token. Sonst könnten Dritte fremde Endpunkte ersetzen. Push funktioniert nur in sicheren Kontexten (HTTPS).