PaymentRequest: show() 方法

可用性有限

此特性不是基線特性,因為它在一些最廣泛使用的瀏覽器中不起作用。

安全上下文: 此功能僅在安全上下文(HTTPS)中可用,且支援此功能的瀏覽器數量有限。

PaymentRequest 介面的 show() 方法指示使用者代理開始向用戶顯示和處理支付請求的使用者介面。

所有文件中,一次只能處理一個支付請求。一旦某個 PaymentRequestshow() 方法被呼叫,任何對 show() 的其他呼叫都將被 AbortError 拒絕,直到返回的 Promise 完成,無論是透過一個 PaymentResponse(指示支付請求的結果)完成,還是被錯誤拒絕。

注意: 實際上,儘管規範規定不能這樣做,但包括 Firefox 在內的一些瀏覽器支援同時有多個活躍的支付請求。

如果您的架構在呼叫 show() 例項化支付介面時,不一定準備好所有資料,請指定 detailsPromise 引數,提供一個在資料準備好後完成的 Promise。如果提供了此引數,show() 將不允許使用者與支付介面互動,直到該 Promise 完成,以便在使用者開始支付過程之前更新資料。

處理結果,並在必要時呼叫 PaymentResponse.retry() 重試失敗的支付,都可以非同步或同步完成,具體取決於您的需求。為了獲得最佳使用者體驗,非同步解決方案通常是最佳選擇。MDN 和其他地方的大多數示例都使用 async/await 非同步等待結果驗證等。

語法

js
show()
show(details)

引數

details 可選

一個物件或一個解析為物件的 Promise。如果您的架構要求在例項化支付介面和使用者開始與其互動之間更新支付請求的詳細資訊,請提供此引數。該物件應包含更新後的資訊。

displayItems 可選

一個物件陣列,每個物件描述支付請求的一個行專案。這些代表收據或發票上的行專案,每個都具有以下屬性:

amount

一個描述專案貨幣值的物件。此物件包含以下欄位:

currency

一個字串,包含一個有效的 3 字母 ISO 4217 貨幣識別符號 (ISO 4217),指示用於支付 value 的貨幣。

value

一個字串,包含一個有效的十進位制值,表示構成支付金額的貨幣數量。此字串必須只包含一個可選的開頭“-”以表示負值,然後是一個或多個 0 到 9 的數字,以及一個可選的小數點(“.”,不考慮區域設定),後跟至少一個數字。不允許有空格。

label

一個字串,指定收費專案或服務的可讀名稱或描述。根據介面的設計,使用者代理可能會向用戶顯示此資訊。

pending

一個布林值,如果指定的 amount 尚未最終確定,則為 true。這可用於顯示取決於送貨地址、送貨選項等選擇的運費或稅費等專案。使用者代理可以顯示此資訊,但不是必需的。

error 可選 已廢棄 非標準

一個字串,指定要呈現給使用者的錯誤訊息。當呼叫 updateWith() 時,在更新資料中包含 error 會導致 使用者代理 顯示文字作為一般錯誤訊息。對於地址欄位特定的錯誤,請使用 shippingAddressErrors 欄位。

modifiers 可選

一個物件陣列,每個物件描述特定支付方法識別符號的修飾符,每個都具有以下屬性:

supportedMethods

一個字串,表示支付方法識別符號。支付方法識別符號僅在使用者選擇此支付方法時適用。

total 可選

一個物件,如果使用者選擇了此支付方法,它將覆蓋 detailsPromise 引數的 total 屬性。該屬性接受與 detailsPromise 引數的 total 屬性相同的輸入。

additionalDisplayItems 可選

一個 Array 物件,如果使用者選擇了此支付方法,它將提供附加顯示專案,這些專案將附加到 detailsPromise 引數的 displayItems 屬性。此屬性通常用於新增折扣或附加費行專案,以指示所選支付方法不同總金額的原因,使用者代理可以顯示這些資訊。該屬性接受與 detailsPromise 引數的 displayItems 屬性相同的輸入。

data 可選

一個可序列化物件,提供受支援的支付方法可能需要的可選資訊。

例如,您可以使用它根據所選支付方式調整總支付金額(“5% 現金折扣!”)。

shippingAddressErrors 可選 已廢棄 非標準

一個物件,其中包含配送地址的每個無法驗證的屬性的錯誤訊息。

shippingOptions 可選 已廢棄 非標準

一個物件陣列,每個物件描述使用者可能選擇的一個可用配送選項。

total 可選

一個具有與 displayItems 中的物件相同屬性的物件,提供更新後的支付總額。請確保此值等於 displayItems 中所有專案的總和。這不是自動計算的。無論何時總欠款金額髮生變化,您都必須自行更新此值。這讓您可以靈活處理稅費、折扣和對總價格的其他調整。

返回值

一個最終解析為 PaymentResponsePromise。當用戶接受支付請求時(例如透過單擊瀏覽器支付表中的“支付”按鈕),Promise 將被解析。

異常

Promise 拒絕時,不會丟擲異常,而是返回異常。

AbortError DOMException

如果 使用者代理 已經顯示支付面板,則返回此錯誤。在使用者代理載入的所有文件中,一次只能顯示一個支付面板。

如果使用者取消支付請求,Promise 也會被 AbortError 拒絕。

InvalidStateError DOMException

如果此請求已顯示相同的支付(其狀態為 interactive,因為它已經顯示),則返回此錯誤。

NotSupportedError DOMException

如果在呼叫 PaymentRequest 建構函式時使用者代理不支援指定的支付方法,則返回此錯誤。

SecurityError DOMException

如果呼叫 show() 不是響應使用者操作(例如 clickkeyup 事件)而發出的,則返回此錯誤。丟擲 SecurityError 的其他原因由使用者代理自行決定,可能包括在短時間內呼叫 show() 次數過多,或在家長控制阻止支付請求時呼叫 show() 等情況。

安全

需要瞬態使用者啟用。使用者必須與頁面或 UI 元素互動才能使此功能正常工作。

用法說明

使用 show() 最常見的模式涉及 async/await 語法或使用 show().then().catch() 來處理響應和任何可能的拒絕。它們看起來像這樣:

async/await 語法

使用 await 等待 Promise 解析,可以特別清晰地編寫處理支付的程式碼。

js
async function processPayment() {
  try {
    const payRequest = new PaymentRequest(methodData, details, options);

    payRequest.onshippingaddresschange = (ev) =>
      ev.updateWith(checkAddress(payRequest));
    payRequest.onshippingoptionchange = (ev) =>
      ev.updateWith(checkShipping(payRequest));

    const response = await payRequest.show();
    await validateResponse(response);
  } catch (err) {
    /* handle the error; AbortError usually means a user cancellation */
  }
}

在此程式碼中,方法 checkAddress()checkShipping() 分別檢查送貨地址和送貨選項的更改,並響應提供一個物件或一個返回物件的 Promise;此物件包含 PaymentResponse 中已更改或需要更改的欄位。

下面的 validateResponse() 方法在 show() 返回後被呼叫,以檢視返回的 response 並提交支付或拒絕支付為失敗。

js
async function validateResponse(response) {
  try {
    if (await checkAllValues(response)) {
      await response.complete("success");
    } else {
      await response.complete("fail");
    }
  } catch (err) {
    await response.complete("fail");
  }
}

在這裡,一個名為 checkAllValues() 的自定義函式檢視 response 中的每個值並確保它們有效,如果每個欄位都有效則返回 true,如果任何欄位無效則返回 false。當且僅當每個欄位都有效時,在響應上呼叫 complete() 方法並傳入字串 "success",這表示一切都有效並且支付可以相應完成。

如果任何欄位具有不可接受的值,或者前面的程式碼丟擲異常,則呼叫 complete() 並傳入字串 "fail",這表示支付過程完成但失敗。

您也可以選擇在響應物件上呼叫 retry(),而不是立即失敗,以要求使用者代理嘗試再次處理支付;這通常只應在使用者對訂單進行任何必要的更正後進行。

最後,啟動支付過程就像呼叫 processPayment() 方法一樣簡單。

then/catch 語法

您也可以使用較舊的基於 Promise 的方法來處理支付,使用 show() 返回的 Promise 上的 then()catch() 函式。

js
function processPayment() {
  const payRequest = new PaymentRequest(methodData, details, options);

  payRequest.onshippingaddresschange = (ev) =>
    ev.updateWith(checkAddress(payRequest));
  payRequest.onshippingoptionchange = (ev) =>
    ev.updateWith(checkShipping(payRequest));

  payRequest
    .show()
    .then((response) => validateResponse(response))
    .catch((err) => handleError(err));
}

這在功能上等同於使用 await 語法的 processPayment() 方法。

js
function validateResponse(response) {
  checkAllValues(response)
    .then((response) => response.complete("success"))
    .catch((response) => response.complete("fail"));
}

你甚至可以讓 checkAllValues() 成為一個同步函式,儘管這可能會帶來你不希望處理的效能影響。

js
function validateResponse(response) {
  if (checkAllValues(response)) {
    response.complete("success");
  } else {
    response.complete("fail");
  }
}

如果您需要更多關於使用 Promise 的資訊,請參閱文章 使用 Promise

示例

在以下示例中,在呼叫 show() 方法之前例項化一個 PaymentRequest 物件。此方法觸發使用者代理內建的從使用者那裡獲取支付資訊的流程。當用戶互動完成時,show() 方法返回一個解析為 PaymentResponse 物件的 Promise。然後,開發人員使用 PaymentResponse 物件中的資訊格式化並向伺服器傳送支付資料。您應該非同步地將支付資訊傳送到伺服器,以便對 paymentResponse.complete() 的最終呼叫可以指示支付的成功或失敗。

js
button.onclick = async () => {
  // Initialization of PaymentRequest arguments are excerpted for the sake of
  // brevity.
  const payment = new PaymentRequest(methods, details, options);
  try {
    const response = await payment.show();
    // Process response here, including sending payment instrument
    // (e.g., credit card) information to the server.
    // paymentResponse.methodName contains the selected payment method
    // paymentResponse.details contains a payment method specific response
    await response.complete("success");
  } catch (err) {
    console.error("Uh oh, something bad happened", err.message);
  }
};

以下示例展示瞭如何在向終端使用者呈現支付表單時更新它。

js
async function requestPayment() {
  // We start with AU$0 as the total.
  const initialDetails = {
    total: {
      label: "Total",
      amount: { value: "0", currency: "AUD" },
    },
  };
  const request = new PaymentRequest(methods, initialDetails, options);
  // Check if the user supports the `methods`
  if (!(await request.canMakePayment())) {
    return; // no, so use a web form instead.
  }
  // Let's update the total as the sheet is shown
  const updatedDetails = {
    total: {
      label: "Total",
      amount: { value: "20", currency: "AUD" },
    },
  };
  const response = await request.show(updatedDetails);
  // Check response, etc.
}

document.getElementById("buyButton").onclick = requestPayment;

規範

規範
Payment Request API
# dom-paymentrequest-show

瀏覽器相容性

另見