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

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

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

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

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

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

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

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

Возврат платежных данных клиента

Когда клиент авторизует платеж, интерфейс может отправить почтовое сообщение работнику службы для продолжения. Вы можете разрешить обещание, переданное в 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;
     

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

Чтобы клиент мог отменить транзакцию, интерфейсная часть может отправить для этого почтовое сообщение работнику службы. Затем сервисный работник может разрешить обещание, переданное в 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://payhandler-demo.glitch.me

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

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

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

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

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

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