Start · Sprachen · JavaScript · Referenz · PaymentRequestEvent.openWindow()

PaymentRequestEvent.openWindow()

Methode

Öffnet im Service Worker eines Payment Handlers eine Seite mit derselben Herkunft in einem neuen Fenster, damit Nutzer die Zahlung bestätigen können.

seit JavaScript Experimentell: Chromium-Browser (Chrome/Edge 70+), Kategorie: webapi

Signatur

PaymentRequestEvent.prototype.openWindow(url)

Beschreibung

openWindow() gehört zur Payment Handler API und kann nur im Service Worker einer webbasierten Zahlungs-App aufgerufen werden, und zwar innerhalb des paymentrequest-Events. Ruft ein Händler PaymentRequest.show() auf und wählt der Nutzer diese Zahlungs-App aus, bekommt der Service Worker ein PaymentRequestEvent. Mit openWindow() öffnet er dann eine Oberfläche, etwa zum Anmelden, zur Auswahl einer Karte oder zur Bestätigung einer Zwei-Faktor-Abfrage.

Die URL muss dieselbe Herkunft (Origin) haben wie der Payment Handler. Relative URLs werden relativ zum Skript des Service Workers aufgelöst. Der Browser zeigt das Fenster meist als modales Zahlungsfenster über der Händlerseite an, nicht als normalen Tab.

Normalerweise ruft man openWindow() zusammen mit event.respondWith() auf. Man übergibt ein Promise, das erst dann mit den Zahlungsdaten erfüllt wird, wenn das geöffnete Fenster sie per postMessage() an den Service Worker zurückgeschickt hat. Diese Antwort ist ein PaymentHandlerResponse-Objekt mit methodName und details.

Parameter

Name Typ Default Beschreibung
$url Pflicht string URL der Seite, die geöffnet werden soll. Sie muss dieselbe Herkunft wie der Payment Handler haben. Relative Pfade werden relativ zum Service-Worker-Skript aufgelöst.

Rückgabewert

Typ
Promise<WindowClient | null>
Beschreibung
Ein Promise, das mit einem WindowClient für das geöffnete Fenster erfüllt wird. Es wird mit null erfüllt, wenn das Fenster zwar geöffnet wurde, aber nicht als Client zugeordnet werden kann. Ist die URL ungültig oder das Öffnen nicht erlaubt, wird das Promise abgelehnt, z. B. mit TypeError oder NotAllowedError.

Beispiele

Zahlungsfenster im Service Worker öffnen

// sw.js – Service Worker des Payment Handlers
let resolver = null;
let paymentEvent = null;

self.addEventListener('paymentrequest', (event) => {
  paymentEvent = event;

  event.respondWith(new Promise((resolve, reject) => {
    resolver = { resolve, reject };

    event.openWindow('/pay/checkout.html')
      .then((client) => {
        if (client === null) {
          reject(new Error('Zahlungsfenster konnte nicht geöffnet werden'));
        }
      })
      .catch(reject);
  }));
});

Antwort aus dem Fenster an den Service Worker weitergeben

// sw.js – Nachrichten aus dem Zahlungsfenster verarbeiten
self.addEventListener('message', (event) => {
  const { type, payload } = event.data ?? {};

  if (type === 'READY') {
    // Fenster fragt nach Betrag und Händlerdaten
    event.source.postMessage({
      type: 'PAYMENT_INFO',
      total: paymentEvent.total,
      origin: paymentEvent.topOrigin
    });
  } else if (type === 'CONFIRM') {
    resolver?.resolve({
      methodName: 'https://pay.example.com',
      details: { token: payload.token }
    });
  } else if (type === 'CANCEL') {
    resolver?.reject(new Error('Vom Nutzer abgebrochen'));
  }
});

Geöffnete Seite: Daten anzeigen und bestätigen

// /pay/checkout.html – eingebundenes Skript
const sw = navigator.serviceWorker;

sw.addEventListener('message', ({ data }) => {
  if (data.type === 'PAYMENT_INFO') {
    const { currency, value } = data.total;
    document.querySelector('#amount').textContent = `${value} ${currency}`;
    document.querySelector('#merchant').textContent = data.origin;
  }
});

sw.controller.postMessage({ type: 'READY' });

document.querySelector('#pay').addEventListener('click', () => {
  sw.controller.postMessage({ type: 'CONFIRM', payload: { token: 'tok_123' } });
});

document.querySelector('#cancel').addEventListener('click', () => {
  sw.controller.postMessage({ type: 'CANCEL' });
});

// Wichtig · Fallstricke

  • Experimentell: Die Payment Handler API gibt es nur in Chromium-Browsern. Prüfe vorher, ob sie verfügbar ist, z. B. mit 'PaymentRequestEvent' in self im Service Worker oder mit 'paymentManager' in registration.
  • Gleiche Herkunft: URLs mit anderer Herkunft werden abgelehnt. Wenn du nach extern weiterleiten willst (z. B. zu einer Bank), öffne zuerst eine Seite mit eigener Herkunft und leite von dort weiter.
  • Nur im Event-Kontext: Die Methode funktioniert nur, solange das paymentrequest-Event aktiv ist. Rufe event.respondWith() daher synchron auf und öffne das Fenster darin. Ein späterer Aufruf, etwa nach einem await außerhalb von respondWith, kann mit InvalidStateError oder NotAllowedError fehlschlagen.
  • Setze Daten aus dem Fenster (z. B. event.data) nie ungeprüft ins DOM ein. So vermeidest du XSS-Lücken. Achte auch darauf, dass methodName in der Antwort zu einer der vom Händler angeforderten Zahlungsmethoden passt.
  • Wenn der Nutzer das Fenster schließt, ohne zu antworten, bleibt das Promise aus respondWith() offen. Browser brechen die Zahlung dann meist selbst ab. Trotzdem solltest du einen Abbruch sauber mit reject behandeln.