서비스 워커를 사용한 결제 트랜잭션 조정

웹 기반 결제 앱을 웹 결제에 맞게 조정하고 고객에게 더 나은 사용자 환경을 제공하는 방법

결제 앱이 등록되면 판매자의 결제 요청을 수락할 수 있습니다. 이 게시물에서는 런타임 (창이 표시되고 사용자가 창과 상호작용할 때)에 서비스 워커에서 결제 거래를 조정하는 방법을 설명합니다.

서비스 워커로 결제 거래 조정
서비스 워커로 결제 거래 조정

'런타임 결제 매개변수 변경사항'은 사용자가 결제 핸들러와 상호작용하는 동안 판매자와 결제 핸들러가 메시지를 교환할 수 있는 이벤트 집합을 의미합니다. 서비스 워커로 선택적 결제 정보 처리에서 자세히 알아보세요.

판매자로부터 결제 요청 이벤트 수신

고객이 웹 기반 결제 앱으로 결제하기로 선택하고 판매자가 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 호출자의 출처를 나타내는 문자열입니다. 이는 판매자가 Payment Request API를 직접 호출하는 경우 topOrigin와 같을 수 있지만, 결제 게이트웨이와 같은 서드 파티가 iframe 내에서 API를 호출하는 경우에는 다를 수 있습니다.
paymentRequestId Payment Request API에 제공된 PaymentDetailsInitid 속성입니다. 판매자가 생략하면 브라우저에서 자동 생성된 ID를 제공합니다.
methodData 판매자가 PaymentMethodData의 일부로 제공한 결제 수단별 데이터입니다. 이 ID를 사용하여 결제 거래 세부정보를 확인합니다.
total 판매자가 PaymentDetailsInit의 일부로 제공한 총 금액입니다. 이를 사용하여 고객에게 총 결제 금액을 알리는 UI를 구성합니다.
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 });
}

프런트엔드에서 준비 신호 수신

결제 핸들러 창이 열리면 서비스 워커는 결제 앱 프런트엔드의 준비 상태 신호를 기다려야 합니다. 서비스 워커는 준비가 되면 중요한 정보를 프런트엔드에 전달할 수 있습니다.

[payment handler] 프런트엔드:

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

[payment handler] 프런트엔드:

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 판매자가 결제를 처리하는 데 필요한 정보를 제공하는 결제 수단별 데이터입니다.

[payment handler] 프런트엔드:

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

결제 거래 취소

고객이 거래를 취소할 수 있도록 프런트엔드는 서비스 워커에 게시 메시지를 전송하여 이를 실행할 수 있습니다. 그러면 서비스 워커는 null를 사용하여 PaymentRequestEvent.respondWith()에 전달된 약속을 확인하여 거래가 취소되었음을 판매자에게 알릴 수 있습니다.

[payment handler] 프런트엔드:

  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

[payment handler] 서비스 워커

[payment handler] 프런트엔드

사용해 보려면 다음 단계를 따르세요.

  1. https://paymentrequest-demo.glitch.me/로 이동합니다.
  2. 페이지 하단으로 이동합니다.
  3. 결제 수단 추가 버튼을 누릅니다.
  4. 결제 수단 식별자 필드에 https://paymenthandler-demo.glitch.me를 입력합니다.
  5. 입력란 옆에 있는 결제 버튼을 누릅니다.

다음 단계

이 도움말에서는 서비스 워커에서 결제 거래를 조정하는 방법을 알아봤습니다. 다음 단계는 서비스 워커에 몇 가지 고급 기능을 추가하는 방법을 알아보는 것입니다.