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

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

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

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

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

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

고객이 개발자의 웹 기반 결제 앱으로 결제하도록 선택하고 판매자가 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과 동일할 수 있지만, API가 서드 파티(예: 결제 게이트웨이)에 의해 iframe 내에서 호출되는 경우에는 다를 수 있습니다.
paymentRequestId Payment Request API에 제공된 PaymentDetailsInitid 속성입니다. 판매자가 이를 생략하면 브라우저에서 자동 생성된 ID를 제공합니다.
methodData PaymentMethodData의 일부로 판매자가 제공하는 결제 수단별 데이터입니다. 결제 거래 세부정보를 확인하는 데 사용합니다.
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 });
}

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

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

[결제 핸들러] 프런트엔드:

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://paymenthandler-demo.glitch.me

[결제 핸들러] 서비스 워커

[결제 핸들러] 프런트엔드

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

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

다음 단계

이 문서에서는 서비스 워커에서 결제 트랜잭션을 조정하는 방법을 알아보았습니다. 다음 단계는 서비스 워커에 고급 기능을 추가하는 방법을 알아보는 것입니다.