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

浏览器兼容性

另见