Zahlungstransaktionen mit einem Service Worker orchestrieren

So passen Sie Ihre webbasierte Zahlungs-App an Webzahlungen an und bieten Kunden eine bessere Nutzererfahrung.

Sobald die Zahlungs-App registriert ist, können Sie Zahlungsanfragen von Händlern annehmen. In diesem Beitrag wird erläutert, wie eine Zahlungstransaktion von einem Service Worker während der Laufzeit organisiert wird, also wenn ein Fenster angezeigt wird und der Nutzer damit interagiert.

Zahlungstransaktionen mit einem Service Worker orchestrieren
Zahlungstransaktionen mit einem Service Worker orchestrieren

„Änderungen an Zahlungsparametern zur Laufzeit“ bezieht sich auf eine Reihe von Ereignissen, mit denen der Händler und der Zahlungsabwickler Nachrichten austauschen können, während der Nutzer mit dem Zahlungsabwickler interagiert. Weitere Informationen finden Sie unter Optionale Zahlungsinformationen mit einem Service Worker verarbeiten.

Ereignis „Zahlungsanfrage“ vom Händler erhalten

Wenn ein Kunde mit Ihrer webbasierten Zahlungs-App bezahlen möchte und der Händler PaymentRequest.show() aufruft, erhält Ihr Service Worker das Ereignis paymentrequest. Fügen Sie dem Dienst-Worker einen Ereignis-Listener hinzu, um das Ereignis zu erfassen und sich auf die nächste Aktion vorzubereiten.

[payment handler] service-worker.js:

…
let payment_request_event;
let resolver;
let client;

// `self` is the global object in service worker
self.addEventListener('paymentrequest', async e => {
  if (payment_request_event) {
    // If there's an ongoing payment transaction, reject it.
    resolver.reject();
  }
  // Preserve the event for future use
  payment_request_event = e;
…

Die aufbewahrte PaymentRequestEvent enthält wichtige Informationen zu dieser Transaktion:

Property-Name Beschreibung
topOrigin Ein String, der den Ursprung der Startseite der Website angibt (in der Regel der Zahlungsempfänger). Hiermit wird die Händlerherkunft angegeben.
paymentRequestOrigin Ein String, der den Ursprung des Aufrufers angibt. Dieser Wert kann mit topOrigin übereinstimmen, wenn der Händler die Payment Request API direkt aufruft. Er kann sich jedoch unterscheiden, wenn die API von einem Drittanbieter wie einem Zahlungs-Gateway innerhalb eines iFrames aufgerufen wird.
paymentRequestId Die id-Eigenschaft der PaymentDetailsInit, die an die Payment Request API übergeben wird. Wenn der Händler dies unterlässt, stellt der Browser eine automatisch generierte ID bereit.
methodData Die zahlungsmethodespezifischen Daten, die vom Händler im Rahmen von PaymentMethodData bereitgestellt werden. Anhand dieser Informationen kannst du die Details der Zahlungstransaktion ermitteln.
total Der vom Händler im Rahmen von PaymentDetailsInit angegebene Gesamtbetrag. Erstelle damit eine Benutzeroberfläche, auf der der Kunde den zu zahlenden Gesamtbetrag sehen kann.
instrumentKey Der vom Nutzer ausgewählte Instrumentschlüssel. Dieser Wert entspricht dem von Ihnen im Voraus angegebenen instrumentKey. Ein leerer String bedeutet, dass der Nutzer keine Instrumente angegeben hat.

Öffnen Sie das Fenster für den Zahlungsabwickler, um das Frontend der webbasierten Zahlungs-App aufzurufen.

Wenn ein paymentrequest-Ereignis empfangen wird, kann die Zahlungs-App ein Fenster für den Zahlungsabwickler öffnen, indem PaymentRequestEvent.openWindow() aufgerufen wird. Im Fenster des Zahlungsabwicklers wird den Kunden die Benutzeroberfläche Ihrer Zahlungs-App angezeigt, über die sie sich authentifizieren, die Versandadresse und -optionen auswählen und die Zahlung autorisieren können. Wie Sie den Frontend-Code schreiben, erfahren Sie im Artikel Zahlungen über das Zahlungs-Frontend verarbeiten (demnächst verfügbar).

Direkter Bezahlvorgang mit einer webbasierten Zahlungs-App.

Übergeben Sie eine gespeicherte Zusicherung an PaymentRequestEvent.respondWith(), damit Sie sie in Zukunft mit einem Zahlungsergebnis abschließen können.

[payment handler] service-worker.js:

…
self.addEventListener('paymentrequest', async e => {
…
  // Retain a promise for future resolution
  // Polyfill for PromiseResolver is provided below.
  resolver = new PromiseResolver();

  // Pass a promise that resolves when payment is done.
  e.respondWith(resolver.promise);
  // Open the checkout page.
  try {
    // Open the window and preserve the client
    client = await e.openWindow(checkoutURL);
    if (!client) {
      // Reject if the window fails to open
      throw 'Failed to open window';
    }
  } catch (err) {
    // Reject the promise on failure
    resolver.reject(err);
  };
});
…

Mit einer praktischen PromiseResolver-Polyfill können Sie ein Versprechen zu einem beliebigen Zeitpunkt auflösen.

class PromiseResolver {
  constructor() {
    this.promise_ = new Promise((resolve, reject) => {
      this.resolve_ = resolve;
      this.reject_ = reject;
    })
  }
  get promise() { return this.promise_ }
  get resolve() { return this.resolve_ }
  get reject() { return this.reject_ }
}

Informationen mit dem Frontend austauschen

Der Service Worker der Zahlungs-App kann über ServiceWorkerController.postMessage() Nachrichten mit der Frontend-Ansicht der Zahlungs-App austauschen. Wenn du Nachrichten vom Frontend erhalten möchtest, musst du message-Ereignisse überwachen.

[payment handler] service-worker.js:

// Define a convenient `postMessage()` method
const postMessage = (type, contents = {}) => {
  if (client) client.postMessage({ type, ...contents });
}

Bereit-Signal vom Frontend empfangen

Sobald das Fenster des Zahlungsabwicklers geöffnet ist, sollte der Dienst-Worker auf ein Signal zum Bereitschaftsstatus vom Frontend der Zahlungs-App warten. Der Dienst-Worker kann wichtige Informationen an das Frontend weitergeben, wenn er bereit ist.

[payment handler] frontend:

navigator.serviceWorker.controller.postMessage({
  type: 'WINDOW_IS_READY'
});

[payment handler] service-worker.js:

…
// Received a message from the frontend
self.addEventListener('message', async e => {
  let details;
  try {
    switch (e.data.type) {
      // `WINDOW_IS_READY` is a frontend's ready state signal
      case 'WINDOW_IS_READY':
        const { total } = payment_request_event;
…

Transaktionsdetails an das Frontend übergeben

Senden Sie uns jetzt die Zahlungsdetails zurück. In diesem Fall senden Sie nur den Gesamtbetrag der Zahlungsanfrage. Sie können aber auch weitere Details angeben.

[payment handler] service-worker.js:

…
        // Pass the payment details to the frontend
        postMessage('PAYMENT_IS_READY', { total });
        break;
…

[payment handler] frontend:

let total;

navigator.serviceWorker.addEventListener('message', async e => {
  switch (e.data.type) {
      case 'PAYMENT_IS_READY':
        ({ total } = e.data);
        // Update the UI
        renderHTML(total);
        break;
…

Zahlungsdaten des Kunden zurückgeben

Wenn der Kunde die Zahlung autorisiert, kann das Frontend eine Postnachricht an den Service Worker senden, um fortzufahren. Du kannst das an PaymentRequestEvent.respondWith() übergebene Versprechen erfüllen, um das Ergebnis an den Händler zurückzugeben. Geben Sie ein PaymentHandlerResponse-Objekt an.

Property-Name Beschreibung
methodName Die Zahlungsmethoden-ID, die für die Zahlung verwendet wurde.
details Die zahlungsmethodespezifischen Daten, die dem Händler die erforderlichen Informationen zur Zahlungsverarbeitung liefern.

[payment handler] frontend:

  const paymentMethod = …

  postMessage('PAYMENT_AUTHORIZED', {
    paymentMethod,              // Payment method identifier
  });

[payment handler] service-worker.js:

…
// Received a message from the frontend
self.addEventListener('message', async e => {
  let details;
  try {
    switch (e.data.type) {
      …
      case 'PAYMENT_AUTHORIZED':
        // Resolve the payment request event promise
        // with a payment response object
        const response = {
          methodName: e.data.paymentMethod,
          details: { id: 'put payment credential here' },
        }
        resolver.resolve(response);
        // Don't forget to initialize.
        payment_request_event = null;
        break;
      …

Zahlungstransaktion stornieren

Damit der Kunde die Transaktion abbrechen kann, kann das Frontend eine Postnachricht an den Service Worker senden. Der Service Worker kann dann das an PaymentRequestEvent.respondWith() übergebene Versprechen mit null auflösen, um dem Händler zu signalisieren, dass die Transaktion abgebrochen wurde.

[payment handler] frontend:

  postMessage('CANCEL_PAYMENT');

[payment handler] service-worker.js:

…
// Received a message from the frontend
self.addEventListener('message', async e => {
  let details;
  try {
    switch (e.data.type) {
      …
      case 'CANCEL_PAYMENT':
        // Resolve the payment request event promise
        // with null
        resolver.resolve(null);
        // Don't forget to initialize.
        payment_request_event = null;
        break;
      …

Beispielcode

Alle Beispielcodes in diesem Dokument waren Auszüge aus der folgenden funktionsfähigen Beispiel-App:

https://paymenthandler-demo.glitch.me

[payment handler] service worker

[payment handler] frontend

So kannst du es ausprobieren:

  1. Rufen Sie https://paymentrequest-demo.glitch.me/ auf.
  2. Sehen Sie sich den Bereich ganz unten auf der Seite an.
  3. Drücken Sie auf die Schaltfläche Zahlungsmethode hinzufügen.
  4. Geben Sie https://paymenthandler-demo.glitch.me in das Feld Zahlungsmethode-ID ein.
  5. Drücke neben dem Feld auf die Schaltfläche Bezahlen.

Nächste Schritte

In diesem Artikel haben wir gelernt, wie eine Zahlungstransaktion über einen Dienst-Worker orchestriert wird. Im nächsten Schritt erfahren Sie, wie Sie dem Dienstanbieter einige erweiterte Funktionen hinzufügen.