Организация платежных транзакций с помощью сервис-воркера

Как адаптировать ваше платежное веб-приложение к веб-платежам и обеспечить лучший пользовательский интерфейс для клиентов.

После регистрации платежного приложения вы готовы принимать платежные запросы от продавцов. В этой статье объясняется, как организовать платежную транзакцию от service worker во время выполнения (т. е. когда отображается окно и пользователь взаимодействует с ним).

Организация платежных операций с помощью сервисного работника
Организация платежных операций с помощью сервисного работника

«Изменения параметров платежа во время выполнения» относятся к набору событий, которые позволяют продавцу и обработчику платежей обмениваться сообщениями, пока пользователь взаимодействует с обработчиком платежей. Узнайте больше в разделе Обработка необязательной информации о платеже с помощью сервисного работника .

Получите событие запроса платежа от продавца

Когда клиент выбирает оплату с помощью вашего веб-приложения для оплаты и продавец вызывает PaymentRequest.show() , ваш service worker получит событие paymentrequest . Добавьте прослушиватель событий к service worker, чтобы захватить событие и подготовиться к следующему действию.

[обработчик платежей] 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;

Сохраненный PaymentRequestEvent содержит важную информацию об этой транзакции:

Имя свойства Описание
topOrigin Строка, указывающая источник веб-страницы верхнего уровня (обычно это продавец-получатель). Используйте ее для идентификации источника продавца.
paymentRequestOrigin Строка, указывающая источник вызывающего. Это может быть то же самое, что и topOrigin , когда продавец вызывает API запроса платежа напрямую, но может быть иным, если API вызывается из iframe третьей стороной, например платежным шлюзом.
paymentRequestId Свойство id PaymentDetailsInit , предоставленное API запроса платежа. Если торговец его не указывает, браузер предоставит автоматически сгенерированный идентификатор.
methodData Данные о способе оплаты, предоставленные продавцом как часть PaymentMethodData . Используйте это для определения деталей платежной транзакции.
total Общая сумма, предоставленная продавцом как часть PaymentDetailsInit . Используйте это для создания пользовательского интерфейса, чтобы сообщить клиенту общую сумму к оплате.
instrumentKey Ключ инструмента, выбранный пользователем. Это отражает instrumentKey вы указали заранее. Пустая строка означает, что пользователь не указал никаких инструментов.

Откройте окно обработчика платежей, чтобы отобразить интерфейс веб-приложения для оплаты.

При получении события paymentrequest платежное приложение может открыть окно обработчика платежей, вызвав PaymentRequestEvent.openWindow() . Окно обработчика платежей представит клиентам интерфейс вашего платежного приложения, где они могут пройти аутентификацию, выбрать адрес доставки и параметры, а также авторизовать платеж. Мы рассмотрим, как написать код интерфейса, в разделе Обработка платежей на платежном интерфейсе (скоро).

Процесс оформления заказа с использованием веб-приложения для оплаты.

Передайте сохраненное обещание в PaymentRequestEvent.respondWith() чтобы в будущем можно было разрешить его с результатом платежа.

[обработчик платежей] 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);
  };
});

Вы можете использовать удобный полифилл PromiseResolver для разрешения обещания в произвольный момент времени.

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

Обмен информацией с фронтендом

Сервисный работник платежного приложения может обмениваться сообщениями с фронтендом платежного приложения через ServiceWorkerController.postMessage() . Чтобы получать сообщения от фронтенда, прослушивайте события message .

[обработчик платежей] service-worker.js:

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

Получите сигнал готовности от интерфейса

После открытия окна обработчика платежей сервисный работник должен дождаться сигнала о готовности от интерфейса платежного приложения. Сервисный работник может передать важную информацию на интерфейс, когда он будет готов.

[обработчик платежей] интерфейс:

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

[обработчик платежей] 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;

Передать данные транзакции на фронтенд

Теперь отправьте обратно реквизиты платежа. В этом случае вы отправляете только общую сумму платежного запроса, но вы можете передать больше деталей, если хотите.

[обработчик платежей] service-worker.js:


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

[обработчик платежей] интерфейс:

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;

Верните платежные данные клиента

Когда клиент авторизует платеж, frontend может отправить сообщение post в service worker для продолжения. Вы можете разрешить обещание, переданное в PaymentRequestEvent.respondWith() , чтобы отправить результат обратно продавцу. Передайте объект PaymentHandlerResponse .

Имя свойства Описание
methodName Идентификатор способа оплаты, использованного для совершения платежа.
details Данные о способе оплаты, которые предоставляют продавцу необходимую информацию для обработки платежа.

[обработчик платежей] интерфейс:

  const paymentMethod = 

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

[обработчик платежей] 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;
      

Отменить платежную транзакцию

Чтобы позволить клиенту отменить транзакцию, frontend может отправить сообщение post в service worker, чтобы сделать это. Service worker может затем разрешить обещание, переданное в PaymentRequestEvent.respondWith() , с null , чтобы указать торговцу, что транзакция была отменена.

[обработчик платежей] интерфейс:

  postMessage('CANCEL_PAYMENT');

[обработчик платежей] 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;
      

Пример кода

Все примеры кодов, которые вы видели в этом документе, были выдержками из следующего рабочего примера приложения:

https://paymenthandler-demo.glitch.me

[обработчик платежей] работник службы

[обработчик платежей] фронтенд

Чтобы попробовать:

  1. Перейдите по ссылке https://paymentrequest-demo.glitch.me/ .
  2. Перейти к концу страницы.
  3. Нажмите кнопку Добавить платеж .
  4. Введите https://paymenthandler-demo.glitch.me в поле «Идентификатор способа оплаты» .
  5. Нажмите кнопку «Оплатить» рядом с полем.

Следующие шаги

В этой статье мы узнали, как организовать платежную транзакцию от service worker. Следующий шаг — научиться добавлять некоторые более продвинутые функции в service worker.