Organizowanie transakcji płatniczych z użyciem skryptu service worker

Jak dostosować internetową aplikację do płatności do płatności internetowych i zapewnić klientom lepsze wrażenia.

Gdy aplikacja płatnicza zostanie zarejestrowana, będziesz mieć możliwość akceptowania próśb o płatność od sprzedawców. Z tego artykułu dowiesz się, jak zarządzać transakcją płatności z użyciem service workera w czasie działania aplikacji (czyli gdy wyświetla się okno i użytkownik wchodzi z nim w interakcję).

Organizowanie transakcji płatniczych za pomocą usługi roboczej
Zarządzanie transakcjami płatniczymi za pomocą usługi workera

„Zmiany parametrów płatności w czasie wykonywania” to zbiór zdarzeń, które umożliwiają wymianę wiadomości między sprzedawcą a podmiotem obsługującym płatności, gdy użytkownik wchodzi w interakcję z tym podmiotem. Więcej informacji znajdziesz w artykule Obsługa opcjonalnych informacji o płatnościach za pomocą service workera.

Odbieranie zdarzenia prośby o płatność od sprzedawcy

Gdy klient zdecyduje się zapłacić za pomocą Twojej internetowej aplikacji do płatności, a sprzedawca wywoła funkcjęPaymentRequest.show(), Twój serwis worker otrzyma zdarzenie paymentrequest. Dodaj do serwisowego workera listenera zdarzeń, aby rejestrować zdarzenia i przygotowywać się do wykonania kolejnej czynności.

[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;
…

Zapisane PaymentRequestEvent zawiera ważne informacje o tej transakcji:

Nazwa usługi Opis
topOrigin Ciąg znaków wskazujący pochodzenie strony najwyższego poziomu (zwykle sprzedawca, który jest płatnikiem). Używaj go do identyfikacji sprzedawcy.
paymentRequestOrigin Ciąg znaków wskazujący pochodzenie wywołującego. Może ona być taka sama jak topOrigin, gdy sprzedawca wywołuje interfejs Payment Request API bezpośrednio, ale może być inna, jeśli interfejs API jest wywoływany z poziomu ramki osadzonej przez osobę trzecią, np. bramkę płatniczą.
paymentRequestId Właściwość id obiektu PaymentDetailsInit przekazanego do interfejsu Payment Request API. Jeśli sprzedawca pominie ten parametr, przeglądarka poda automatycznie wygenerowany identyfikator.
methodData Dane dotyczące formy płatności, które sprzedawca udostępnia w ramach PaymentMethodData. Służy do określania szczegółów transakcji płatniczej.
total Łączna kwota podana przez sprzedawcę w ramach PaymentDetailsInit. Użyj tego, aby utworzyć interfejs użytkownika, który poinformuje klienta o łącznej kwocie do zapłaty.
instrumentKey Klucz instrumentu wybrany przez użytkownika. Odpowiada to podanym wcześniej instrumentKey. Pusty ciąg wskazuje, że użytkownik nie podał żadnych instrumentów.

Otwórz okno modułu do obsługi płatności, aby wyświetlić frontend aplikacji do płatności internetowej

Gdy zostanie odebrane zdarzenie paymentrequest, aplikacja do płatności może otworzyć okno menedżera płatności, wywołując PaymentRequestEvent.openWindow(). Okno menedżera płatności wyświetli klientom interfejs Twojej aplikacji do płatności, w którym mogą uwierzytelnić się, wybrać adres dostawy i opcje oraz autoryzować płatność. W artykule Obsługa płatności na interfejsie płatności (wkrótce) omówimy, jak pisać kod interfejsu.

Proces płatności w aplikacji do płatności internetowej.

Przekaż zachowane zobowiązanie do PaymentRequestEvent.respondWith(), aby móc je rozwiązać w przyszłości za pomocą płatności.

[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);
  };
});
…

Możesz użyć wygodnego PromiseResolverpolyfill, aby rozwiązać obietnicę w dowolnym momencie.

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_ }
}

Wymiana informacji z frontendem

Worker usługi aplikacji do płatności może wymieniać wiadomości z interfejsem aplikacji za pomocą ServiceWorkerController.postMessage(). Aby otrzymywać wiadomości z interfejsu, nasłuchuj zdarzenia message.

[payment handler] service-worker.js:

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

Odbieranie sygnału gotowości z front-endu

Gdy okno modułu do obsługi płatności zostanie otwarte, skrypt service worker powinien oczekiwać sygnału o gotowości z interfejsu aplikacji do płatności. Gdy usługa jest gotowa, może przekazać ważne informacje do frontendu.

[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;
…

Przekazywanie szczegółów transakcji do frontendu

Teraz prześlij szczegóły płatności. W tym przypadku wysyłasz tylko łączną kwotę prośby o płatność, ale możesz też podać więcej szczegółów.

[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;
…

zwracanie danych do płatności klienta;

Gdy klient autoryzuje płatność, interfejs może wysłać wiadomość do service workera, aby kontynuować. Możesz zrealizować obietnicę przekazaną do PaymentRequestEvent.respondWith(), aby wysłać wynik z powrotem do sprzedawcy. Przekaz obiekt PaymentHandlerResponse.

Nazwa usługi Opis
methodName Identyfikator formy płatności użytej do dokonania płatności.
details Dane dotyczące formy płatności, które zawierają informacje potrzebne sprzedawcy do przetworzenia płatności.

[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;
      …

Anulowanie transakcji płatności

Aby umożliwić klientowi anulowanie transakcji, interfejs może wysłać wiadomość do service workera. Service worker może następnie spełnić obietnicę przekazaną do PaymentRequestEvent.respondWith() z wartością null, aby poinformować sprzedawcę, że transakcja została anulowana.

[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;
      …

Przykładowy kod

Wszystkie przykładowe kody w tym dokumencie to fragmenty działającej przykładowej aplikacji:

https://paymenthandler-demo.glitch.me

[payment handler] service worker

[payment handler] frontend

Aby to zrobić:

  1. Otwórz stronę https://paymentrequest-demo.glitch.me/.
  2. Przewiń do dołu strony.
  3. Naciśnij przycisk Dodaj formę płatności.
  4. W polu Identyfikator formy płatności wpisz https://paymenthandler-demo.glitch.me.
  5. Kliknij przycisk Zapłać obok pola.

Dalsze kroki

Z tego artykułu dowiesz się, jak zorganizować transakcję płatniczą z użyciem service workera. W następnym kroku dowiesz się, jak dodać do usługi nieco bardziej zaawansowane funkcje.