與服務工作人員協調付款交易

如何將網頁版付款應用程式改用 Web Payments,為客戶提供更優質的使用者體驗。

註冊付款應用程式後,即可接受商家的付款要求。本文將說明如何在執行階段 (也就是顯示視窗並與其互動時) 從服務工作者協調付款交易。

使用服務工作者協調付款交易
使用服務工作者自動化調度管理付款交易

「執行階段付款參數變更」是指一組事件,可讓商家和付款處理程式在使用者與付款處理程式互動時交換訊息。如要進一步瞭解如何處理選用付款資訊,請參閱「使用服務工作者處理選用付款資訊」一文。

接收來自商家的付款要求事件

當消費者選擇使用您的網路付款應用程式付款,且商家叫用 PaymentRequest.show() 時,服務工作者會收到 paymentrequest 事件。將事件監聽器新增至服務工作站,以便擷取事件並準備執行下一個動作。

[payment handler] 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 中提供的付款方式專屬資料。用於判斷付款交易詳細資料。
total 商家提供的 PaymentDetailsInit 總金額。您可以使用這項資訊建構使用者介面,讓消費者瞭解應付款的總金額。
instrumentKey 使用者選取的樂器鍵。這會反映您先前提供的 instrumentKey。空白字串表示使用者未指定任何儀器。

開啟付款處理常式視窗,顯示以網頁為基礎的付款應用程式前端

收到 paymentrequest 事件時,支付應用程式可以呼叫 PaymentRequestEvent.openWindow() 來開啟支付處理常式視窗。付款處理程式視窗會向客戶顯示付款應用程式的介面,方便他們驗證身分、選擇運送地址和選項,以及授權付款。我們將在「在付款前端處理付款」(即將推出) 一文中介紹如何編寫前端程式碼。

使用網路付款應用程式的結帳流程。

將已保留的承諾傳遞至 PaymentRequestEvent.respondWith(),以便日後透過付款結果解決。

[payment handler] 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 polyfill,在任意時間解析承諾。

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 事件。

[payment handler] service-worker.js:

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

從前端接收就緒信號

付款處理常式視窗開啟後,服務工作者應等待付款應用程式前端傳送的準備就緒信號。服務工作者可在準備就緒時,將重要資訊傳遞至前端。

[payment handler] frontend:

navigator.serviceWorker.controller.postMessage({
  type
: 'WINDOW_IS_READY'
});

[payment handler] 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;

將交易詳細資料傳遞至前端

請回傳付款詳細資料。在這種情況下,您只需傳送付款要求的總金額,但您也可以傳送更多詳細資料。

[payment handler] service-worker.js:


       
// Pass the payment details to the frontend
        postMessage
('PAYMENT_IS_READY', { total });
       
break;

[payment handler] frontend:

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 用於付款的付款方式 ID。
details 付款方式專屬資料,可提供商家處理付款所需的資訊。

[payment handler] frontend:

  const paymentMethod = 

  postMessage
('PAYMENT_AUTHORIZED', {
    paymentMethod
,              // Payment method identifier
 
});

[payment handler] 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] frontend:

  postMessage('CANCEL_PAYMENT');

[payment handler] 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] frontend

如要試用這項功能,請按照下列步驟操作:

  1. 前往 https://paymentrequest-demo.glitch.me/
  2. 前往頁面底部。
  3. 按下「新增付款按鈕」
  4. 在「付款方式 ID」欄位中輸入 https://paymenthandler-demo.glitch.me
  5. 按下欄位旁的「付款」按鈕。

後續步驟

在本文中,我們瞭解如何透過服務工作者協調付款交易。接下來,我們將說明如何在服務工作者中新增進階功能。