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

«Изменение параметров платежа во время выполнения» — это набор событий, позволяющий продавцу и обработчику платежей обмениваться сообщениями во время взаимодействия пользователя с обработчиком платежей. Подробнее см. в статье «Обработка необязательной платежной информации с помощью сервисного работника» .
Получение события запроса платежа от продавца
 Когда покупатель выбирает оплату через ваше веб-приложение для оплаты, а продавец вызывает 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;
      …
Пример кода
Все примеры кодов, которые вы видели в этом документе, являются выдержками из следующего: Демонстрация обработчика платежей
Следующие шаги
В этой статье мы узнали, как организовать платёжную транзакцию через сервис-воркер. Следующий шаг — научиться добавлять в сервис-воркер более продвинутые функции.
