การจัดการธุรกรรมการชำระเงินกับ Service Worker

วิธีปรับเปลี่ยนแอปการชำระเงินบนเว็บของคุณให้เป็น Web Payments และมอบประสบการณ์ของผู้ใช้ที่ดียิ่งขึ้นให้แก่ลูกค้า

เมื่อลงทะเบียนแอปการชำระเงินแล้ว คุณก็พร้อมที่จะยอมรับคำขอการชำระเงินจากผู้ขาย โพสต์นี้จะอธิบายวิธีจัดกลุ่มธุรกรรมการชำระเงินจาก Service Worker ระหว่างรันไทม์ (เช่น เมื่อหน้าต่างแสดงขึ้นและผู้ใช้กำลังโต้ตอบด้วย)

การจัดการธุรกรรมการชำระเงินกับ Service Worker เป็นกลุ่ม
การจัดการธุรกรรมการชำระเงินเป็นกลุ่มกับ Service Worker

"การเปลี่ยนแปลงพารามิเตอร์การชำระเงินรันไทม์" หมายถึงชุดเหตุการณ์ที่อนุญาตให้ผู้ขายและเครื่องจัดการการชำระเงินแลกเปลี่ยนข้อความขณะที่ผู้ใช้โต้ตอบกับเครื่องจัดการการชำระเงิน ดูข้อมูลเพิ่มเติมในการจัดการข้อมูลการชำระเงินที่ไม่บังคับด้วย Service Worker

รับเหตุการณ์คำขอการชำระเงินจากผู้ขาย

เมื่อลูกค้าเลือกชำระเงินด้วยแอปการชำระเงินบนเว็บและผู้ขายเรียกใช้ PaymentRequest.show() โปรแกรมทำงานของบริการจะได้รับเหตุการณ์ paymentrequest เพิ่ม Listener เหตุการณ์ให้กับโปรแกรมทำงานของบริการเพื่อบันทึกเหตุการณ์และเตรียมพร้อมสำหรับการดำเนินการถัดไป

[เครื่องจัดการการชำระเงิน] 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 เมื่อผู้ขายเรียกใช้ Payment Request API โดยตรง แต่อาจแตกต่างจากนี้หาก API เรียกใช้จากภายใน iframe โดยบุคคลที่สาม เช่น เกตเวย์สำหรับการชำระเงิน
paymentRequestId พร็อพเพอร์ตี้ id ของ PaymentDetailsInit ที่ระบุใน Payment Request API หากผู้ขายละเว้น เบราว์เซอร์จะแสดงรหัสที่สร้างขึ้นโดยอัตโนมัติ
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);
  };
});
…

คุณสามารถใช้ Polyfill ของ 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_ }
}

แลกเปลี่ยนข้อมูลกับฟรอนท์เอนด์

Service Worker ของแอปการชำระเงินจะแลกเปลี่ยนข้อความกับฟรอนท์เอนด์ของแอปการชำระเงินได้ผ่าน 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;
      …

ยกเลิกธุรกรรมการชำระเงิน

หากต้องการอนุญาตให้ลูกค้ายกเลิกธุรกรรม ฟรอนท์เอนด์สามารถส่งข้อความโพสต์ไปยัง Service Worker เพื่อดำเนินการดังกล่าวได้ จากนั้น Service Worker จะแก้ไขคำสัญญาที่ส่งไปยัง 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

[เครื่องจัดการการชำระเงิน] Service Worker

[เครื่องจัดการการชำระเงิน] ฟรอนท์เอนด์

วิธีทดลองใช้มีดังนี้

  1. ไปที่ https://paymentrequest-demo.glitch.me/
  2. ไปที่ด้านล่างสุดของหน้า
  3. กดปุ่มเพิ่มการชำระเงิน
  4. ป้อน https://paymenthandler-demo.glitch.me ลงในช่องตัวระบุวิธีการชำระเงิน
  5. กดปุ่มชำระเงินข้างช่อง

ขั้นตอนถัดไป

ในบทความนี้ เราได้เรียนรู้วิธีจัดการธุรกรรมการชำระเงินจาก Service Worker เป็นกลุ่ม ขั้นตอนต่อไปคือดูวิธีเพิ่มฟีเจอร์ขั้นสูงอื่นๆ ให้กับโปรแกรมทำงานของบริการ