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

PaymentRequestEvent.respondWith()

Methode

Verhindert die Standardverarbeitung eines <code>paymentrequest</code>-Events im Service Worker und liefert stattdessen ein Promise auf die Antwort des Zahlungshandlers.

seit JavaScript Payment Handler API — experimentell, nur Chromium- Kategorie: webapi

Signatur

PaymentRequestEvent.prototype.respondWith(promise)

Beschreibung

respondWith() ist das zentrale Werkzeug einer webbasierten Zahlungs-App, die über die Payment Handler API im Service Worker implementiert ist. Ruft eine Händlerseite new PaymentRequest(...).show() auf und wählt der Nutzer Ihre Zahlungs-App aus, empfängt Ihr Service Worker ein paymentrequest-Event vom Typ PaymentRequestEvent. Mit respondWith() teilen Sie dem Browser mit, dass Sie die Zahlung selbst abwickeln und das Ergebnis später liefern.

Als Argument übergeben Sie ein Promise, das mit einem PaymentHandlerResponse-Objekt erfüllt wird. Es enthält mindestens methodName (die genutzte Zahlungsmethode) und details (methodenspezifische Daten wie ein Token), optional Versand- und Zahlerdaten. Der Browser gibt diese Daten als PaymentResponse an das Promise von show() auf der Händlerseite weiter.

Typischerweise öffnen Sie innerhalb des Events mit event.openWindow() ein Fenster, in dem sich der Nutzer anmeldet und die Zahlung bestätigt. Das Fenster kommuniziert per postMessage mit dem Service Worker, der daraufhin das an respondWith() übergebene Promise auflöst. Wird das Promise abgelehnt, erhält die Händlerseite einen Fehler (meist AbortError) und die Zahlung gilt als abgebrochen.

Parameter

Name Typ Default Beschreibung
$promise Pflicht Promise<PaymentHandlerResponse> | PaymentHandlerResponse Promise (oder direkter Wert), das mit einem Objekt { methodName, details, payerName?, payerEmail?, payerPhone?, shippingAddress?, shippingOption? } erfüllt wird. Eine Ablehnung bricht die Zahlung ab.

Beispiele

Einfache Zahlungsantwort im Service Worker

// sw.js — Service Worker der Zahlungs-App
self.addEventListener('paymentrequest', (event) => {
  console.log('Betrag:', event.total.value, event.total.currency);

  // Direkt eine Antwort liefern (z. B. für Tests)
  event.respondWith(Promise.resolve({
    methodName: 'https://pay.example.com',
    details: { token: 'tok_demo_123' }
  }));
});
Betrag: 49.90 EUR

Zahlungsfenster öffnen und auf Bestätigung warten

// sw.js
let resolver = null;

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

    // Checkout-Seite der Zahlungs-App öffnen
    event.openWindow('/checkout.html').catch((err) => {
      reject(err);
      resolver = null;
    });
  }));
});

// Nachricht aus /checkout.html empfangen
self.addEventListener('message', (event) => {
  if (!resolver) return;
  const { type, token } = event.data;

  if (type === 'confirm') {
    resolver.resolve({
      methodName: 'https://pay.example.com',
      details: { token }
    });
  } else {
    resolver.reject(new DOMException('Vom Nutzer abgebrochen', 'AbortError'));
  }
  resolver = null;
});

Gegenstück auf der Checkout-Seite

// checkout.html — sendet das Ergebnis an den Service Worker
const sendToSW = (data) => navigator.serviceWorker.controller?.postMessage(data);

document.querySelector('#pay').addEventListener('click', async () => {
  const res = await fetch('/api/authorize', { method: 'POST' });
  const { token } = await res.json();
  sendToSW({ type: 'confirm', token });
});

document.querySelector('#cancel').addEventListener('click', () => {
  sendToSW({ type: 'cancel' });
});

Händlerseite: Antwort empfangen

// shop.js — Seite des Händlers
const request = new PaymentRequest(
  [{ supportedMethods: 'https://pay.example.com' }],
  { total: { label: 'Summe', amount: { currency: 'EUR', value: '49.90' } } }
);

try {
  const response = await request.show();
  console.log(response.methodName, response.details);
  await response.complete('success');
} catch (err) {
  console.log('Zahlung abgebrochen:', err.name);
}
https://pay.example.com { token: 'tok_demo_123' }

// Wichtig · Fallstricke

  • Synchron aufrufen: respondWith() muss während der synchronen Event-Verarbeitung aufgerufen werden, nicht erst nach einem await – sonst wirft der Browser InvalidStateError. Asynchrone Logik gehört in das übergebene Promise.
  • Nur einmal: Ein zweiter Aufruf pro Event wirft ebenfalls InvalidStateError.
  • Offene Promises: Bleibt das Promise dauerhaft unerfüllt (z. B. Nutzer schließt das Fenster), hängt die Zahlung. Behandeln Sie Abbrüche daher aktiv, etwa über eine Abbruch-Nachricht oder Zeitüberschreitung.
  • Sicherheit: Nur in sicheren Kontexten (HTTPS) verfügbar. Prüfen Sie in message-Handlern die Herkunft (event.source/event.origin) und senden Sie in details keine rohen Kartendaten, sondern Tokens.
  • Kompatibilität: Die Payment Handler API ist experimentell und nur in Chromium-Browsern implementiert; Firefox und Safari unterstützen sie nicht. Die Payment-App muss vorher über registration.paymentManager bzw. ein Web-App-Manifest registriert sein.