Signatur
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
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 selfim 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. Rufeevent.respondWith()daher synchron auf und öffne das Fenster darin. Ein späterer Aufruf, etwa nach einemawaitaußerhalb vonrespondWith, kann mitInvalidStateErroroderNotAllowedErrorfehlschlagen. - Setze Daten aus dem Fenster (z. B.
event.data) nie ungeprüft ins DOM ein. So vermeidest du XSS-Lücken. Achte auch darauf, dassmethodNamein 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 mitrejectbehandeln.