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

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

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

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

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

รับกิจกรรมคำขอการชำระเงินจากผู้ขาย

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

[ตัวจัดการการชำระเงิน] 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_ }
}

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

โปรแกรมทำงานของบริการแอปสำหรับการชำระเงินจะแลกเปลี่ยนข้อความกับส่วนหน้าของแอปสำหรับการชำระเงินได้ผ่านทาง ServiceWorkerController.postMessage() หากต้องการรับข้อความจากฟรอนท์เอนด์ ให้ฟังเหตุการณ์ message

[ตัวจัดการการชำระเงิน] service-worker.js:

// Define a convenient `postMessage()` method
const postMessage = (type, contents = {}) => {
  if (client) client.postMessage({ type, ...contents });
}

รับสัญญาณที่พร้อมใช้งานจากฟรอนท์เอนด์

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

ฟรอนท์เอนด์ของ [ตัวจัดการการชำระเงิน]

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. กดปุ่มชำระเงินถัดจากช่อง

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

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