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

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