支付请求 API

W3C 候选推荐标准草案

关于本文档的更多详情
此版本:
https://www.w3.org/TR/2025/CRD-payment-request-20250402/
最新发布版本:
https://www.w3.org/TR/payment-request/
最新编辑草案:
https://w3c.github.io/payment-request/
历史:
https://www.w3.org/standards/history/payment-request/
提交历史
测试套件:
https://wpt.live/payment-request/
实现报告:
https://w3c.github.io/test-results/payment-request/all.html
最新推荐标准:
https://www.w3.org/TR/2022/REC-payment-request-20220908/
编辑:
Marcos Cáceres (Apple Inc.)
Rouslan Solomakhin (Google)
Ian Jacobs (W3C)
前任编辑:
Domenic Denicola (Google)
Adrian Bateman (Microsoft Corporation)
Zach Koch (Google)
Roy McElmurry (Facebook)
Danyao Wang (Google)
反馈:
GitHub w3c/payment-request (拉取请求, 新建问题, 待解决问题)
浏览器支持:
caniuse.com

摘要

本规范标准化了一个 API,允许商家(即销售实体或数字商品的网站)以最少的集成来利用一种或多种支付方式。用户代理(例如浏览器)促进商家和用户之间的支付流程。

本文档的状态

本节描述了本文档发布时的状态。当前的 W3C 出版物列表以及本技术报告的最新修订版可以在位于 https://www.w3.org/TR/ 的 W3C 标准和草案索引中找到。

2022 年 9 月,Web 支付工作组发布了 Payment Request Recommendation。经过隐私和国际化审查后,该推荐标准排除了与账单和送货地址相关的功能。然而,实现一直在互操作地支持这些功能,因此工作组决定尝试使规范与实现重新对齐,并就相关问题重新与社区进行沟通。

本文档是基于原始推荐标准文本的候选推荐标准快照。随后的候选推荐标准草案将重新添加地址功能以及自推荐标准发布以来所做的一些其他更改。

作为重新添加地址支持的一部分,本规范现在引用 Contact Picker API 中定义的地址组件,而不是自行定义这些组件。实际上,Contact Picker API 源自 Payment Request API 中的原始定义,并从规范中分离出来,因为地址在 Web 上的用途超出了支付范围。

工作组计划在将规范推进到建议推荐标准状态之前进行讨论并遵循通常的审查流程。

工作组将通过生成实现报告来展示实现经验。该报告将显示两个或多个独立实现在测试套件中通过每个强制性测试(即,每个测试对应于规范的 MUST 要求)。

本文档由 Web 支付工作组作为候选推荐标准草案发布,采用推荐标准流程

作为候选推荐标准发布并不意味着 W3C 及其成员的认可。候选推荐标准草案整合了工作组打算包含在后续候选推荐标准快照中的先前候选推荐标准的更改。

这是一份草案文件,可能随时被其他文件更新、替换或废弃。引用本文档作为正在进行的工作以外的任何内容都是不合适的。 本规范的未来更新可能会包含新功能

本文档由一个在W3C 专利政策下运作的小组制作。 W3C 维护一个与该小组的可交付成果相关的任何专利披露的公开列表;该页面还包括披露专利的说明。任何实际知晓某项专利且认为该专利包含基本权利要求的个人必须按照W3C 专利政策第 6 节的规定披露该信息。

本文档受 2023年11月3日 W3C 流程文档的约束。

1. 引言

本节是非规范性的。

本规范描述了一个 API,该 API 允许 用户代理 (例如浏览器)在交易中的三方之间充当媒介:

支付方式定义了:

可选的 附加数据类型
可选地,一个 IDL 类型,支付方式期望将其作为 PaymentMethodDatadata 成员接收。如果未为给定的支付方式指定,则不进行 IDL 转换,支付方式将以 JSON 格式接收 data
验证支付方式数据的步骤
指定支付方式在将其转换为支付方式的附加数据类型后如何验证 PaymentMethodDatadata 成员的算法步骤。如果未为给定的支付方式指定,则不进行验证。

对于给定的支付方式,如何完成支付请求的详细信息是支付处理程序的实现细节,支付处理程序是处理支付请求的应用程序或服务。具体来说,支付处理程序定义了:

检查是否可以进行支付的步骤
支付处理程序如何确定其本身或用户是否可能“进行支付”也是支付处理程序的实现细节。
响应支付请求的步骤
返回商家用于处理或验证交易的对象或字典的步骤。此对象的结构特定于每个支付方式
用户更改支付方式时的步骤(可选)

描述如何处理用户更改支付方式或货币工具(例如,从借记卡更改为信用卡)的步骤,这些步骤会产生字典object或 null。

此 API 还使网站能够利用更安全的支付方案(例如,令牌化和系统级身份验证),这些方案是标准 JavaScript 库无法实现的。这有可能减少商家的责任,并有助于保护敏感的用户信息。

1.1 目标和范围

以下内容超出了本规范的范围:

2. 使用示例

本节是非规范性的。

为了使用该 API,开发者需要提供并跟踪一些关键信息。这些信息作为参数传递给 PaymentRequest 构造函数,并随后用于更新向用户显示的支付请求。具体来说,这些信息是:

一旦构造了 PaymentRequest,它就会通过 show() 方法呈现给最终用户。 show() 返回一个 promise,一旦用户确认支付请求,该 promise 就会产生一个 PaymentResponse

2.1 声明多种支付方式

在构造新的 PaymentRequest 时,商家使用第一个参数 (methodData) 来列出用户可以支付的不同方式(例如,信用卡、Apple Pay、Google Pay 等)。更具体地说,methodData 序列包含 PaymentMethodData 字典,其中包含商家接受的支付方式支付方式标识符以及任何相关的支付方式特定数据(例如,支持哪些信用卡网络)。

示例 1: `methodData` 参数
const methodData = [
    {
    supportedMethods: "https://example.com/payitforward",
    data: {
        payItForwardField: "ABC",
    },
    },
    {
    supportedMethods: "https://example.com/bobpay",
    data: {
        merchantIdentifier: "XXXX",
        bobPaySpecificField: true,
    },
    },
];

2.2 描述支付内容

在构造新的 PaymentRequest 时,商家使用构造函数的第二个参数 (details) 来提供要求用户完成的交易的详细信息。这包括订单的总额,以及可选的一些行项目,这些行项目可以提供所支付内容的详细分类。

示例 2: `details` 参数
const details = {
    id: "super-store-order-123-12312",
    displayItems: [
    {
        label: "Sub-total",
        amount: { currency: "GBP", value: "55.00" },
    },
    {
        label: "Value-Added Tax (VAT)",
        amount: { currency: "GBP", value: "5.00" },
    },
    ],
    total: {
    label: "Total due",
    // The total is GBP£65.00 here because we need to
    // add shipping (below). The selected shipping
    // costs GBP£5.00.
    amount: { currency: "GBP", value: "65.00" },
    },
};

2.3 添加配送选项

这里我们看到了一个如何向 details 添加两个配送选项的示例。

示例 3: 添加配送选项
const shippingOptions = [
    {
    id: "standard",
    // Shipping by truck, 2 days
    label: "🚛  Envío por camión (2 dias)",
    amount: { currency: "EUR", value: "5.00" },
    selected: true,
    },
    {
    id: "drone",
    // Drone shipping, 2 hours
    label: "🚀 Drone Express (2 horas)",
    amount: { currency: "EUR", value: "25.00" }
    },
];
Object.assign(details, { shippingOptions });

2.4 对支付请求的条件修改

这里我们看到了如何为在特定网络上使用卡添加处理费。请注意,这需要重新计算总额。

示例 4: 根据卡类型修改支付请求
// Certain cards incur a $3.00 processing fee.
const cardFee = {
    label: "Card processing fee",
    amount: { currency: "AUD", value: "3.00" },
};

// Modifiers apply when the user chooses to pay with
// a card.
const modifiers = [
    {
    additionalDisplayItems: [cardFee],
    supportedMethods: "https://example.com/cardpay",
    total: {
        label: "Total due",
        amount: { currency: "AUD", value: "68.00" },
    },
    data: {
        supportedNetworks: networks,
    },
    },
];
Object.assign(details, { modifiers });

2.5 向最终用户请求特定信息

某些金融交易要求用户提供特定信息,以便商家完成购买(例如,用户的配送地址,以防需要运送实体商品)。要请求此信息,商家可以向 PaymentRequest 构造函数传递第三个可选参数 (options),指明他们需要哪些信息。当显示支付请求时,用户代理将向最终用户请求此信息,并在用户接受支付请求时将其返回给商家。

示例 5: `options` 参数
const options = {
    requestPayerEmail: false,
    requestPayerName: true,
    requestPayerPhone: false,
    requestShipping: true,
}

2.6 构造 PaymentRequest

收集完所有必需的信息后,我们现在可以构造一个 PaymentRequest 并请求浏览器将其呈现给用户:

示例 6: 构造 `PaymentRequest`
async function doPaymentRequest() {
    try {
    const request = new PaymentRequest(methodData, details, options);
    // See below for a detailed example of handling these events
    request.onshippingaddresschange = ev => ev.updateWith(details);
    request.onshippingoptionchange = ev => ev.updateWith(details);
    const response = await request.show();
    await validateResponse(response);
    } catch (err) {
    // AbortError, SecurityError
    console.error(err);
    }
}
async function validateResponse(response) {
    try {
    const errors = await checkAllValuesAreGood(response);
    if (errors.length) {
        await response.retry(errors);
        return validateResponse(response);
    }
    await response.complete("success");
    } catch (err) {
    // Something went wrong...
    await response.complete("fail");
    }
}
// Must be called as a result of a click
// or some explicit user action.
doPaymentRequest();

2.7 处理事件并更新支付请求

在用户同意付款之前,网站有机会根据用户输入更新支付请求。这可以包括,例如,提供额外的配送选项(或修改其成本)、移除无法运送到特定地址的商品等。

示例 7: 注册事件处理程序
const request = new PaymentRequest(methodData, details, options);
// Async update to details
request.onshippingaddresschange = ev => {
    ev.updateWith(checkShipping(request));
};
// Sync update to the total
request.onshippingoptionchange = ev => {
    // selected shipping option
    const { shippingOption } = request;
    const newTotal = {
    currency: "USD",
    label: "Total due",
    value: calculateNewTotal(shippingOption),
    };
    ev.updateWith({ total: newTotal });
};
async function checkShipping(request) {
    try {
    const { shippingAddress } = request;

    await ensureCanShipTo(shippingAddress);
    const { shippingOptions, total } = await calculateShipping(shippingAddress);

    return { shippingOptions, total };
    } catch (err) {
    // Shows error to user in the payment sheet.
    return { error: `Sorry! we can't ship to your address.` };
    }
}

2.8 细粒度错误报告

开发者可以使用 PaymentDetailsUpdate 字典的 shippingAddressErrors 成员来指示 ContactAddress 的特定属性存在验证错误。 shippingAddressErrors 成员是一个 AddressErrors 字典,其成员专门标出实际地址中错误的字段,同时还提供有用的错误消息以显示给最终用户。

request.onshippingaddresschange = ev => {
    ev.updateWith(validateAddress(request.shippingAddress));
};
function validateAddress(shippingAddress) {
    const error = "Can't ship to this address.";
    const shippingAddressErrors = {
    city: "FarmVille is not a real place.",
    postalCode: "Unknown postal code for your country.",
    };
    // Empty shippingOptions implies that we can't ship
    // to this address.
    const shippingOptions = [];
    return { error, shippingAddressErrors, shippingOptions };
}

2.9 将支付响应 POST回服务器

预计 PaymentResponse 中的数据将被 POST回服务器进行处理。为了尽可能简单, PaymentResponse 可以使用默认的 toJSON 步骤(即 .toJSON())将对象直接序列化为 JSON。这使得使用 Fetch Standard 将生成的 JSON POST回服务器变得非常简单:

示例 9: 使用 `fetch()` POST
async function doPaymentRequest() {
    const payRequest = new PaymentRequest(methodData, details);
    const payResponse = await payRequest.show();
    let result = "";
    try {
    const httpResponse = await fetch("/process-payment", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: payResponse.toJSON(),
    });
    result = httpResponse.ok ? "success" : "fail";
    } catch (err) {
    console.error(err);
    result = "fail";
    }
    await payResponse.complete(result);
}
doPaymentRequest();

2.10 与跨域 iframe 一起使用

要指示允许跨域 iframe 调用支付请求 API,可以在 iframe 元素上指定 allow 属性以及 "payment" 关键字。

示例 10: 将 Payment Request API 与跨域 iframe 一起使用
<iframe
    src="https://cross-origin.example"
    allow="payment">
</iframe>

如果 iframe 将在支持 Payment Request API 的多个源之间导航,则可以将 allow 设置为 "payment *"Permissions Policy 规范提供了更多详细信息和示例。

3. PaymentRequest 接口

WebIDL[SecureContext, Exposed=Window]
    interface PaymentRequest : EventTarget {
      constructor(
        sequence<PaymentMethodData> methodData,
        PaymentDetailsInit details,
        optional PaymentOptions options = {}
      );
      [NewObject]
      Promise<PaymentResponse> show(optional Promise<PaymentDetailsUpdate> detailsPromise);
      [NewObject]
      Promise<undefined> abort();
      [NewObject]
      Promise<boolean> canMakePayment();
    
      readonly attribute DOMString id;
      readonly attribute ContactAddress? shippingAddress;
      readonly attribute DOMString? shippingOption;
      readonly attribute PaymentShippingType? shippingType;
    
      attribute EventHandler onshippingaddresschange;
      attribute EventHandler onshippingoptionchange;
      attribute EventHandler onpaymentmethodchange;
    };
注意

开发者创建一个 PaymentRequest 来发起支付请求。 这通常与用户启动支付流程相关联(例如,通过激活网站上的“购买”、“支付”或“结账”按钮,在互动游戏中选择“充值”,或在停车场的自助缴费机上付款)。PaymentRequest 允许开发者在用户提供输入时(直到用户批准或拒绝支付请求)与用户代理交换信息。

如果设置了 requestShipping 成员,则会在处理过程中填充 shippingAddressshippingOptionshippingType 属性。

一个 request与支付相关的浏览上下文 是该 PaymentRequest相关全局对象的浏览上下文的 顶级浏览上下文。每个与支付相关的浏览上下文都有一个 支付请求正在显示布尔值,用于防止同时显示多个支付 UI。

支付请求正在显示布尔值仅防止在单个浏览器选项卡中显示多个支付 UI。但是, 支付处理程序可以将用户代理限制为仅在所有浏览器窗口和选项卡中显示一个支付 UI。其他支付处理程序可能允许在不同的浏览器选项卡中显示支付 UI。

3.1 构造函数

PaymentRequest 是使用提供的 PaymentMethodData 序列 methodData(包括任何支付方式特定的 data)、 PaymentDetailsInit detailsPaymentOptions options 构造的。

PaymentRequest(methodData, details, options) 构造函数必须按如下方式操作:

  1. 如果相关全局对象关联 Document允许使用 "payment" 权限,则抛出一个 "SecurityError" DOMException
  2. 建立请求的 ID:
    1. 如果 details.id 缺失,则向 details 添加一个 id 成员,并将其值设置为一个 UUID [RFC4122]。
  3. serializedMethodData 为一个空列表。
  4. 处理支付方式:
    1. 如果 methodData 序列的长度为零,则 抛出一个 TypeError, 可以选择性地通知开发者至少需要一种支付方式
    2. seenPMIs 为空
    3. 对于 methodData 中的每个 paymentMethod
      1. 运行 验证支付方式标识符的步骤,使用 paymentMethod.supportedMethods。 如果返回 false,则抛出一个 RangeError 异常。 可以选择性地通知开发者支付方式标识符无效。
      2. pmi 为使用 基本 URL 解析器解析 paymentMethod.supportedMethods 的结果:
        1. 如果失败,则将 pmi 设置为 paymentMethod.supportedMethods
      3. 如果 seenPMIs 包含 pmi,则抛出一个 RangeError DOMException, 可以选择性地通知开发者此支付方式标识符是重复的。
      4. 追加 pmiseenPMIs
      5. 如果 paymentMethoddata 成员缺失,则令 serializedData 为 null。 否则,令 serializedData 为将 paymentMethod.data 序列化为 JSON 字符串的结果。重新抛出任何异常。
      6. 如果 serializedData 不为 null,并且定义 paymentMethod.supportedMethods 的规范指定了附加数据类型
        1. objectJSON 解析 serializedData 的结果。
        2. idl 为将 object 转换为 附加数据类型的 IDL 值的结果。重新抛出任何异常。

        3. 运行定义 paymentMethod.supportedMethods 的规范中的验证支付方式数据的步骤(如果有),作用于 object。重新抛出任何异常。

          注意

          这些步骤确保尽早捕获任何 IDL 类型转换和验证错误。

      7. 将元组 (paymentMethod.supportedMethods, serializedData) 添加到 serializedMethodData
  5. 处理总额:
    1. 检查并规范化总金额 details.total.amount。 重新抛出任何异常。
  6. 如果 detailsdisplayItems 成员存在,则对于 details.displayItems 中的每个 item
    1. 检查并规范化金额 item.amount。重新抛出任何异常。
  7. selectedShippingOption 为 null。
  8. 如果 optionsrequestShipping 成员存在且设置为 true,则处理配送选项:
    1. options 为一个空的 sequence<PaymentShippingOption>。
    2. 如果 detailsshippingOptions 成员存在,则:
      1. seenIDs 为一个空集。
      2. 对于 details.shippingOptions 中的每个 option
        1. 检查并规范化金额 item.amount。重新抛出任何异常。
        2. 如果 seenIDs 包含 option.id,则抛出一个 TypeError。 可以选择性地通知开发者配送选项 ID 必须唯一。
        3. 否则,将 option.id 追加到 seenIDs
        4. 如果 option.selected 为 true,则将 selectedShippingOption 设置为 option.id
    3. details.shippingOptions 设置为 options
  9. serializedModifierData 为一个空列表。
  10. 处理支付详情修饰符:
    1. modifiers 为一个空的 sequence<PaymentDetailsModifier>。
    2. 如果 detailsmodifiers 成员存在,则:
      1. modifiers 设置为 details.modifiers
      2. 对于 modifiers 中的每个 modifier
        1. 如果 modifiertotal 成员存在,则:
          1. 检查并规范化总金额 modifier.total.amount。 重新抛出任何异常。
        2. 如果 modifieradditionalDisplayItems 成员存在,则对于 modifier.additionalDisplayItems 中的每个 item
          1. 检查并规范化金额 item.amount。 重新抛出任何异常。
        3. 如果 modifierdata 成员缺失,则令 serializedData 为 null。 否则,令 serializedData 为将 modifier.data 序列化为 JSON 字符串的结果。重新抛出任何异常。
        4. 将元组 (modifier.supportedMethods, serializedData) 添加到 serializedModifierData
        5. 移除 modifierdata 成员(如果存在)。
    3. details.modifiers 设置为 modifiers
  11. request 为一个新的 PaymentRequest
  12. request.[[handler]] 设置为 null
  13. request.[[options]] 设置为 options
  14. request.[[state]] 设置为 "created"。
  15. request.[[updating]] 设置为 false。
  16. request.[[details]] 设置为 details
  17. request.[[serializedModifierData]] 设置为 serializedModifierData
  18. request.[[serializedMethodData]] 设置为 serializedMethodData
  19. request.[[response]] 设置为 null。
  20. requestshippingOption 属性的值设置为 selectedShippingOption
  21. request 上的 shippingAddress 属性的值设置为 null。
  22. 如果 options.requestShipping 设置为 true, 则将 request 上的 shippingType 属性的值设置为 options.shippingType。否则,将其设置为 null。
  23. 返回 request

3.2 id 属性

获取时,id 属性返回此 PaymentRequest[[details]].id

注意

出于审计和对账目的,商家可以将每个交易的唯一标识符与 id 属性关联起来。

3.3 show() 方法

注意

当开发者想要开始支付请求的用户交互时,会调用 show() 方法。 show() 方法返回一个 Promise,当用户接受支付请求时,该 Promise 将被解析。在 show() 方法返回后,将向用户呈现某种用户界面以方便支付请求。

每个支付处理程序控制当多个浏览上下文同时调用 show() 方法时会发生什么。 例如,一些支付处理程序将允许在不同的浏览器选项卡/窗口中显示多个支付 UI。其他支付处理程序可能只允许为整个用户代理显示单个支付 UI。

show(optional detailsPromise) 方法必须按如下方式操作:

  1. request
  2. 如果 request相关全局对象没有 瞬时激活,则用户代理可以
    1. 返回一个被拒绝的 promise,并带有 "SecurityError" DOMException
    注意

    这允许用户代理不需要用户激活,例如支持重定向流程,其中重定向后可能不存在用户激活。有关安全注意事项,请参见 19.9 用户激活要求

    另请参见 问题 #1022,其中讨论了在规范中提供更多关于用户代理何时应该或不应该为 show() 要求用户激活的指导。

  3. 否则, 消耗相关全局对象的用户激活。
  4. documentrequest相关全局对象关联 Document
  5. 如果 document 不是完全激活的,则返回一个被拒绝的 promise,并带有 "AbortError" DOMException
  6. 如果 document可见性状态不是 "visible", 则返回一个被拒绝的 promise,并带有 "AbortError" DOMException
  7. 可选地,如果用户代理希望禁止调用 show() 以保护用户,则返回一个被拒绝的 promise,并带有 "SecurityError" DOMException。例如,用户代理可以限制页面调用 show() 的速率,如 19. 隐私和安全注意事项部分所述。

  8. 如果 request.[[state]] 不是 "created",则返回一个被拒绝的 promise,并带有 "InvalidStateError" DOMException
  9. 如果用户代理支付请求正在显示 布尔值为 true,则:
    1. request.[[state]] 设置为 "closed"。
    2. 返回一个被拒绝的 promise,并带有 "AbortError" DOMException
  10. request.[[state]] 设置为 "interactive"。
  11. acceptPromise一个新的 promise
  12. request.[[acceptPromise]] 设置为 acceptPromise
  13. 可选地:

    1. 用 "AbortError" DOMException 拒绝 acceptPromise
    2. request.[[state]] 设置为 "closed"。
    3. 返回 acceptPromise
    注意

    这允许用户代理自行决定,表现得好像用户立即中止了支付请求。例如,在“隐私浏览”模式或类似模式下,用户代理可能会利用此步骤。

  14. request与支付相关的浏览上下文支付请求正在显示布尔值设置为 true。
  15. 返回 acceptPromise并行执行其余步骤。
  16. handlers 为一个空的列表
  17. 对于 request.[[serializedMethodData]] 中的每个 paymentMethod 元组:
    1. identifierpaymentMethod 元组中的第一个元素。
    2. dataJSON 解析 paymentMethod 元组中第二个元素的结果。
    3. 如果定义 identifier 的规范指定了 附加数据类型,则将 data 转换为该类型的 IDL 值。 否则,将 data 转换为 object
    4. 如果转换导致异常 error
      1. request.[[state]] 设置为 "closed"。
      2. error 拒绝 acceptPromise
      3. request与支付相关的浏览上下文支付请求正在显示布尔值设置为 false。
      4. 终止此算法。
    5. registeredHandlers 为支付方式 identifier 的已注册支付处理程序的列表
      注意: 支付处理程序注册
    6. 对于 registeredHandlers 中的每个 handler
      1. canMakePayment 为运行 handler检查是否可以进行支付的步骤并使用 data 的结果。
      2. 如果 canMakePayment 为 true,则将 handler 追加到 handlers
  18. 如果 handlers 为空,则:
    1. request.[[state]] 设置为 "closed"。
    2. 用 "NotSupportedError" DOMException 拒绝 acceptPromise
    3. request与支付相关的浏览上下文支付请求正在显示布尔值设置为 false。
    4. 终止此算法。
  19. 呈现一个用户界面,允许用户与 handlers 交互。用户代理应该在呈现支付方式时优先考虑用户的偏好。用户界面应该使用与 document文档元素语言(如果有)匹配的语言和基于区域设置的格式,或者如果不可用,则使用适当的回退。

    注意: 支付用户界面的本地化
  20. 如果传递了 detailsPromise,则:
    1. 运行更新 PaymentRequest 详情算法,使用 detailsPromiserequest 和 null。
    2. 等待 detailsPromise 稳定下来。
      注意

      根据 detailsPromise 的稳定方式,更新 PaymentRequest 详情算法决定支付 UI 的行为方式。也就是说,detailsPromise 被拒绝时,支付请求中止。否则,detailsPromise 被满足时,用户代理重新启用支付请求 UI,支付流程可以继续。

  21. request.[[handler]] 设置为最终用户选择的支付处理程序
  22. modifiers 为一个空列表。
  23. 对于 [[serializedModifierData]] 中的每个 tuple
    1. 如果 tuple 的第一个元素(一个 PMI)与 request.[[handler]]支付方式标识符匹配,则将 tuple 的第二个元素(序列化的方法数据)追加到 modifiers
  24. 传递转换后的 paymentMethod 元组中的第二个元素和 modifiers。可选地,用户代理应该request 中的适当数据发送给用户选择的支付处理程序,以指导用户完成支付过程。这包括 request 的各种属性和其他内部插槽(出于隐私原因,在适当的情况下可以排除某些内容)。

    [[serializedModifierData]] 内部插槽中多个适用修饰符的处理是支付处理程序特定的,超出了本规范的范围。然而,建议支付处理程序[[serializedModifierData]] 列表中的项目使用“后来者居上”的方法:也就是说,列表末尾的项目始终优先于列表开头的任何项目(参见下面的示例)。

    acceptPromise 稍后将由用户接受支付请求算法用户中止支付请求算法解析或拒绝,这些算法通过与用户界面的交互触发。

    如果在显示用户界面时 document 不再完全激活,或者在此步骤到达时不再是,则:

    1. 关闭用户界面。
    2. request与支付相关的浏览上下文支付请求正在显示布尔值设置为 false。

3.4 abort() 方法

注意

如果开发者希望告知用户代理中止支付 request 并移除可能显示的任何用户界面,则会调用 abort() 方法。 abort() 只能在调用 show() 方法之后(参见 状态)且在此实例的 [[acceptPromise]] 被解析之前调用。例如,如果他们销售的商品仅在有限的时间内可用,开发者可能会选择这样做。如果用户在允许的时间段内未接受支付请求,则请求将被中止。

用户代理可能并不总是能够中止请求。例如,如果用户代理已将请求的责任委托给另一个应用程序。在这种情况下, abort() 将拒绝返回的 Promise

另请参见用户中止支付请求时的算法。

abort() 方法必须按如下方式操作:

  1. request
  2. 如果 request.[[response]] 不为 null,且 request.[[response]].[[retryPromise]] 不为 null,则返回一个被拒绝的 promise,并带有 “InvalidStateErrorDOMException
  3. 如果 request.[[state]] 的值不是 “interactive”,则返回一个被拒绝的 promise ,并带有 “InvalidStateErrorDOMException
  4. promise一个新的 promise
  5. 返回 promise并行执行其余步骤。
  6. 尝试中止当前与支付处理程序的用户交互,并关闭任何剩余的用户界面。
  7. 用户交互任务源排队一个任务以执行以下步骤:
    1. 如果无法中止当前用户交互, 则用 “InvalidStateErrorDOMException 拒绝 promise 并中止这些步骤。
    2. request.[[state]] 设置为 “closed”。
    3. 用 “AbortErrorDOMException 拒绝 promise request.[[acceptPromise]]
    4. 用 undefined 解析 promise

3.5 canMakePayment() 方法

备注: canMakePayment()

开发者可以使用 canMakePayment() 方法来确定用户代理是否支持所需的支付方式之一。请参阅 19.8 canMakePayment() 保护措施

canMakePayment() 返回 true 并不意味着用户已准备好可用于支付的已配置工具。

canMakePayment() 方法必须运行can make payment 算法

3.6 shippingAddress 属性

当用户提供送货地址时,会填充 PaymentRequestshippingAddress 属性。默认情况下,它为 null。当用户提供送货地址时,会运行送货地址更改算法

3.7 shippingType 属性

PaymentRequestshippingType 属性是用于完成交易的送货类型。其值为 PaymentShippingType 枚举值,如果开发者在构造期间未提供(请参阅 PaymentOptionsshippingType 成员),则为 null。

3.8 onshippingaddresschange 属性

PaymentRequestonshippingaddresschange 属性是名为 shippingaddresschangePaymentRequestUpdateEventEventHandler

3.9 shippingOption 属性

当用户选择送货选项时,会填充 PaymentRequestshippingOption 属性。默认情况下,它为 null。当用户选择送货选项时,会运行送货选项更改算法

3.10 onshippingoptionchange 属性

PaymentRequestonshippingoptionchange 属性是名为 shippingoptionchangePaymentRequestUpdateEventEventHandler

3.11 onpaymentmethodchange 属性

PaymentRequestonpaymentmethodchange 属性是名为 “paymentmethodchange” 的 PaymentMethodChangeEventEventHandler

3.12 内部插槽

PaymentRequest 的实例是使用下表中的内部插槽创建的:

内部插槽 描述 (非规范性)
[[serializedMethodData]] 提供给构造函数的 methodData,但表示为包含支持的方法和字符串或 null 数据的元组(而不是原始对象形式)。
[[serializedModifierData]] 一个列表,其中包含序列 [[details]].modifier 中每个对应项的每个 data 成员的序列化字符串形式,如果不存在此类成员,则为 null。
[[details]] 支付请求的当前 PaymentDetailsBase,最初提供给构造函数,然后通过调用 updateWith() 进行更新。请注意, modifiers 成员中包含的 PaymentDetailsModifier 实例的所有 data 成员都将被删除,因为它们以序列化形式存储在 [[serializedModifierData]] 内部插槽中。
[[options]] 提供给构造函数的 PaymentOptions
[[state]]

支付请求的当前状态,其转换如下:

created
支付请求已构建且尚未呈现给用户。
interactive
支付请求正在呈现给用户。
closed
支付请求已完成。

状态转换如下图所示:

1 构造函数将初始状态设置为 “created”。show() 方法将状态更改为 “interactive”。然后, abort() 方法或任何其他错误都可以将状态发送到“closed”; 同样,用户接受支付请求算法用户中止支付请求算法会将状态更改为 “closed”。
[[updating]] 如果存在用于更新支付请求的待处理 updateWith() 调用,则为 True,否则为 false。
[[acceptPromise]] show() 期间创建的待处理 Promise,如果用户接受支付请求,则该 Promise 将被解析。
[[response]] Null,或由此 PaymentRequest 实例化的 PaymentResponse
[[handler]] 与此 PaymentRequest 关联的支付处理程序。初始化为 null

4. PaymentMethodData 字典

WebIDLdictionary PaymentMethodData {
    required DOMString supportedMethods;
    object data;
};

PaymentMethodData 字典用于指示一组受支持的支付方式以及与这些方式相关的任何支付方式特定数据。

supportedMethods 成员
商家网站接受的支付方式支付方式标识符
data 成员
一个对象,提供受支持的支付方式可能需要的可选信息。如果提供,它将被序列化
备注

supportedMethods 的值已从数组更改为字符串,但为了保持与 Web 上现有内容的兼容性,名称保留为复数形式。

5. PaymentCurrencyAmount 字典

WebIDLdictionary PaymentCurrencyAmount {
  required DOMString currency;
  required DOMString value;
};

PaymentCurrencyAmount 字典用于提供货币金额。

currency 成员

一个 [ISO4217] 格式正确的 3 位字母代码(即不支持数字代码)。它们的规范形式是大写。但是,可用的本地化货币符号的货币代码组合集取决于实现。

显示货币值时,建议用户代理显示货币代码,但用户代理显示货币符号是可选的。这是因为货币符号可能由于在多种不同货币中使用而含糊不清(例如,“$”可能表示美元、澳元、新西兰元、加元等)。

用户代理可以格式化 currency 成员的显示以符合操作系统约定(例如,出于本地化目的)。

注意: 数字货币和 ISO 4217 货币代码

实现本规范的用户代理通过 ECMAScript 的 isWellFormedCurrencyCode 抽象操作强制执行 [ISO4217] 的 3 位字母代码格式,该操作作为 检查和规范化金额算法的一部分被调用。当代码不符合 [ISO4217] 定义的格式时,会抛出 RangeError

因此,当前的实现将允许使用不属于官方 [ISO4217] 列表的格式正确的货币代码(例如,XBT、XRP 等)。如果提供的代码是浏览器知道如何显示的货币,那么实现通常会在用户界面中显示适当的货币符号(例如,“USD”显示为 U+0024 美元符号 ($),“GBP”显示为 U+00A3 英镑符号 (£),“PLN”显示为 U+007A U+0142 兹罗提 (zł),非标准的“XBT”可以显示为 U+0243 带删除线的拉丁大写字母 B (Ƀ))。

ISO 正在努力解决数字货币问题,这可能会导致 [ISO4217] 注册表更新或全新的注册表。社区期望这将解决因使用非标准 3 位字母代码而产生的歧义;例如,“BTC”是指比特币还是未来的不丹货币?在发布时,尚不清楚这种演变将采取何种形式,甚至不清楚工作完成的时间框架。W3C Web 支付工作组正在与 ISO 联络,以便将来对本规范的修订与相关的 ISO 注册表保持兼容。

value 成员
包含货币金额的有效十进制货币值
示例 12: 如何表示 1.234 阿曼里亚尔
{
    "currency": "OMR",
    "value": "1.234"
}

5.1 有效性检查器

如果一个 JavaScript 字符串按给定顺序包含以下代码点,则它是一个有效的十进制货币值

  1. 可选地,一个 U+002D (-),表示金额为负。
  2. 一个或多个 U+0030 (0) 到 U+0039 (9) 范围内的代码点
  3. 可选地,一个 U+002E (.),后跟一个或多个 U+0030 (0) 到 U+0039 (9) 范围内的代码点
注意
以下正则表达式是上述定义的一个实现。
^-?[0-9]+(\.[0-9]+)?$

检查并规范化金额(给定一个 PaymentCurrencyAmount amount),请执行以下步骤:

  1. 如果 IsWellFormedCurrencyCode(amount.currency) 的结果为 false,则抛出一个 RangeError 异常,并可选择通知开发者货币无效。
  2. 如果 amount.value 不是一个有效的十进制货币值,则抛出一个 TypeError,并可选择通知开发者货币无效。
  3. amount.currency 设置为 ASCII 大写 amount.currency 的结果。

检查并规范化总金额(给定一个 PaymentCurrencyAmount amount),请执行以下步骤:

  1. 检查并规范化金额 amount。重新抛出任何异常。
  2. 如果 amount.value 的第一个代码点是 U+002D (-),则抛出一个 TypeError,并可选择通知开发者总额的值不能为负数。
注意: 不更改值

6. 支付详情字典

6.1 PaymentDetailsBase 字典

WebIDLdictionary PaymentDetailsBase {
    sequence<PaymentItem> displayItems;
    sequence<PaymentShippingOption> shippingOptions;
    sequence<PaymentDetailsModifier> modifiers;
};
displayItems 成员
一个 PaymentItem 字典序列,包含用户代理可能显示的支付请求的行项目。
注意
shippingOptions 成员

包含供用户选择的不同送货选项的序列。

如果序列中的某个项目将 selected 成员设置为 true,则这将是默认使用的送货选项,并且 shippingOption 将被设置为此选项的 id,而不会运行 送货选项更改算法。如果序列中有多个项目将 selected 设置为 true,则用户代理会选择序列中的最后一个。

仅当使用 PaymentOptions 构造 PaymentRequest 并且将 requestShipping 设置为 true 时,才会使用 shippingOptions 成员。

注意
modifiers 成员
一个 PaymentDetailsModifier 字典序列,其中包含特定支付方式标识符的修饰符。例如,它允许您根据支付方式调整总金额。

6.2 PaymentDetailsInit 字典

WebIDLdictionary PaymentDetailsInit : PaymentDetailsBase {
    DOMString id;
    required PaymentItem total;
};
注意

除了从 PaymentDetailsBase 字典继承的成员外,以下成员也是 PaymentDetailsInit 字典的一部分:

id 成员
此支付请求的自由格式标识符。
注意
total 成员
一个 PaymentItem,包含支付请求的非负总金额。
注意

6.3 PaymentDetailsUpdate 字典

WebIDLdictionary PaymentDetailsUpdate : PaymentDetailsBase {
    DOMString error;
    PaymentItem total;
    AddressErrors shippingAddressErrors;
    PayerErrors payerErrors;
    object paymentMethodErrors;
};

PaymentDetailsUpdate 字典用于使用 updateWith() 更新支付请求。

除了从 PaymentDetailsBase 字典继承的成员外,以下成员也是 PaymentDetailsUpdate 字典的一部分:

error 成员
一个人类可读的字符串,解释为什么无法将商品运送到所选的送货地址,或任何其他导致没有可用送货选项的原因。当使用 updateWith() 更新支付请求时,如果 PaymentDetailsUpdate 表明没有有效的 shippingOptions(并且 PaymentRequest 是使用 requestShipping 选项设置为 true 构造的),则 PaymentDetailsUpdate 可以在 error 成员中包含一条消息,该消息将显示给用户。
total 成员
一个 PaymentItem,包含一个非负的 amount
注意

本规范中接受 PaymentDetailsUpdate 字典的算法将在 total.amount.value 为负数时抛出异常。

shippingAddressErrors 成员
表示与潜在事件目标关联的送货地址的验证错误。
payerErrors 成员
付款人详细信息相关的验证错误。
paymentMethodErrors 成员

支付方式特定错误。

7. PaymentDetailsModifier 字典

WebIDLdictionary PaymentDetailsModifier {
    required DOMString supportedMethods;
    PaymentItem total;
    sequence<PaymentItem> additionalDisplayItems;
    object data;
};

PaymentDetailsModifier 字典提供了根据支付方式标识符修改 PaymentDetailsBase 的详细信息。 它包含以下成员:

supportedMethods 成员
一个支付方式标识符PaymentDetailsModifier 的成员仅在用户选择此支付方式时适用。
total 成员
一个 PaymentItem 值,它会覆盖 PaymentDetailsInit 字典中针对 supportedMethods 成员的支付方式标识符total 成员。
additionalDisplayItems 成员
一个 PaymentItem 字典序列,提供附加的显示项目,这些项目将附加到 PaymentDetailsBase 字典中的 displayItems 成员,用于 supportedMethods 成员中的支付方式标识符。此成员通常用于添加折扣或附加费行项目,以指示所选支付方式的不同total金额的原因,用户代理可以显示这些项目。
注意

开发者有责任验证 total 金额是 displayItemsadditionalDisplayItems 的总和。

data 成员
一个对象,提供受支持的支付方式可能需要的可选信息。如果提供,它将被序列化

8. PaymentShippingType 枚举

WebIDLenum PaymentShippingType {
    "shipping",
    "delivery",
    "pickup"
};
"shipping"
这是默认值,指的是收集的实际地址作为配送目的地。
"delivery"
这指的是收集的实际地址作为送货目的地。这通常比配送更快。例如,它可以用于食品配送。
"pickup"
这指的是收集的实际地址作为服务取件的一部分。例如,这可以是洗衣取件的地址。

9. PaymentOptions 字典

WebIDLdictionary PaymentOptions {
    boolean requestPayerName = false;
    boolean requestBillingAddress = false;
    boolean requestPayerEmail = false;
    boolean requestPayerPhone = false;
    boolean requestShipping = false;
    PaymentShippingType shippingType = "shipping";
};
注意

PaymentOptions 字典被传递给 PaymentRequest 构造函数,并提供有关支付请求所需选项的信息。

requestBillingAddress 成员
一个布尔值,指示用户代理是否应该收集并返回与支付方式关联的账单地址(例如,与信用卡关联的账单地址)。通常,用户代理会将账单地址作为 PaymentMethodChangeEventmethodDetails 的一部分返回。商家可以使用此信息(例如)在某些司法管辖区计算税款并更新显示的总额。有关公开用户信息的隐私注意事项,请参见下文。
requestPayerName 成员
一个布尔值,指示用户代理是否应该收集并返回付款人的姓名作为支付请求的一部分。例如,将其设置为 true 以允许商家以付款人的名义进行预订。
requestPayerEmail 成员
一个布尔值,指示用户代理是否应该收集并返回付款人的电子邮件地址作为支付请求的一部分。例如,将其设置为 true 以允许商家通过电子邮件发送收据。
requestPayerPhone 成员
一个布尔值,指示用户代理是否应该收集并返回付款人的电话号码作为支付请求的一部分。例如,将其设置为 true 以允许商家致电客户进行账单查询。
requestShipping 成员
一个布尔值,指示用户代理是否应该收集并返回送货地址作为支付请求的一部分。例如,当商家需要将实体商品运送给用户时,将其设置为 true。对于购买数字商品,将其设置为 false。
shippingType 成员
一个 PaymentShippingType 枚举值。某些交易需要实际地址进行交付,但术语“配送”并不合适。例如,“披萨外送”而不是“披萨配送”,“洗衣取件”而不是“洗衣配送”。如果将 requestShipping 设置为 true,则 shippingType 成员会影响用户代理呈现用于收集送货地址的用户界面的方式。

shippingType 成员仅影响支付请求的用户界面。

10. PaymentItem 字典

WebIDLdictionary PaymentItem {
    required DOMString label;
    required PaymentCurrencyAmount amount;
    boolean pending = false;
};

一个或多个 PaymentItem 字典的序列包含在 PaymentDetailsBase 字典中,以指示支付请求的内容和请求的金额。

label 成员
项目的人类可读描述。用户代理可能会向用户显示此描述。
注意: 标签的国际化
amount 成员
一个 PaymentCurrencyAmount,包含项目的货币金额。
pending 成员
一个布尔值。当设置为 true 时,表示 amount 成员不是最终值。这通常用于显示诸如运费或税额之类的项目,这些项目取决于送货地址或送货选项的选择。用户代理可以在支付请求的用户界面中指示待处理字段。

11. PaymentCompleteDetails 字典

WebIDLdictionary PaymentCompleteDetails {
    object? data = null;
};

当支付请求完成时,PaymentCompleteDetails 字典向支付处理程序提供来自商家网站的附加信息。

PaymentCompleteDetails 字典包含以下成员:

data 成员
一个对象,提供 PaymentResponse 关联的支付方式可能需要的可选信息。如果提供,它将被序列化

12. PaymentComplete 枚举

WebIDLenum PaymentComplete {
    "fail",
    "success",
    "unknown"
};
"fail"
表示支付处理失败。用户代理可以显示指示失败的 UI。
"success"
表示支付已成功处理。用户代理可以显示指示成功的 UI。
"unknown"
开发者未指示成功或失败,用户代理不应显示指示成功或失败的 UI。

13. PaymentShippingOption 字典

WebIDLdictionary PaymentShippingOption {
    required DOMString id;
    required DOMString label;
    required PaymentCurrencyAmount amount;
    boolean selected = false;
};

PaymentShippingOption 字典包含描述送货选项的成员。开发者可以通过在响应更改事件时调用 updateWith() 方法,向用户提供一个或多个送货选项。

id 成员
用于引用此 PaymentShippingOption 的字符串标识符。对于给定的 PaymentRequest,它必须是唯一的。
label 成员
项目的人类可读字符串描述。用户代理应该使用此字符串向用户显示送货选项。
amount 成员
一个 PaymentCurrencyAmount,包含项目的货币金额。
selected 成员
一个布尔值。当为 true 时,表示这是序列中默认选定的 PaymentShippingOption用户代理应该在用户界面中默认显示此选项。

14. PaymentResponse 接口

WebIDL[SecureContext, Exposed=Window]
interface PaymentResponse : EventTarget  {
  [Default] object toJSON();

  readonly attribute DOMString requestId;
  readonly attribute DOMString methodName;
  readonly attribute object details;
  readonly attribute ContactAddress? shippingAddress;
  readonly attribute DOMString? shippingOption;
  readonly attribute DOMString? payerName;
  readonly attribute DOMString? payerEmail;
  readonly attribute DOMString? payerPhone;

  [NewObject]
  Promise<undefined> complete(
    optional PaymentComplete result = "unknown",
    optional PaymentCompleteDetails details = {}
  );
  [NewObject]
  Promise<undefined> retry(optional PaymentValidationErrors errorFields = {});

  attribute EventHandler onpayerdetailchange;
};
注意

当用户选择了支付方式并批准了支付请求后,会返回一个 PaymentResponse

14.1 retry() 方法

注意

retry(errorFields) 方法必须按以下方式操作:

  1. responsethis
  2. requestresponse.[[request]]
  3. documentrequest相关全局对象关联 Document
  4. 如果 document 不是完全激活状态,则返回一个被拒绝的 promise,并带有 "AbortError" DOMException
  5. 如果 response.[[complete]] 为 true,则返回一个被拒绝的 promise,并带有 "InvalidStateError" DOMException
  6. 如果 response.[[retryPromise]] 不为 null,则返回一个被拒绝的 promise,并带有 "InvalidStateError" DOMException
  7. request.[[state]] 设置为 "interactive"。
  8. retryPromise一个新的 promise
  9. response.[[retryPromise]] 设置为 retryPromise
  10. 如果传递了 errorFields
    1. 可选地,如果以下任一情况为 true,则在开发者控制台中显示警告:
      1. request.[[options]].requestPayerName 为 false,且 errorFields.payer.name 存在。
      2. request.[[options]].requestPayerEmail 为 false,且 errorFields.payer.email 存在。
      3. request.[[options]].requestPayerPhone 为 false,且 errorFields.payer.phone 存在。
      4. request.[[options]].requestShipping 为 false,且 errorFields.shippingAddress 存在。
    2. 如果传递了 errorFields.paymentMethod 成员,并且如果定义 response.methodName 的规范要求,则将 errorFieldspaymentMethod 成员转换为那里指定的类型的 IDL 值。否则,转换为 object
    3. request支付相关浏览上下文支付请求正在显示布尔值设置为 false。
    4. 如果转换导致异常 error
      1. error 拒绝 retryPromise
      2. 用户代理支付请求正在显示布尔值设置为 false。
      3. 返回。
    5. 通过将 errorFields 的成员与用户代理 UI 中的输入字段匹配,向最终用户指示支付响应的数据存在问题。例如,用户代理可能会在浏览器的 UI 中将用户的注意力吸引到错误的 errorFields,并以有助于用户修复每个错误的方式显示每个字段的值。类似地,如果传递了 error 成员,则在用户代理的 UI 中显示错误。在成员的值为空字符串的情况下,用户代理可以用适当的错误消息替换该值。
  11. 否则,如果未传递 errorFields,则向最终用户发出信号以尝试重试支付。重新启用任何允许最终用户重试接受支付请求的 UI 元素。
  12. 如果在显示用户界面时 document 不再是完全激活状态,或者到达此步骤时不再是,则:
    1. 关闭用户界面。
    2. request支付相关浏览上下文支付请求正在显示布尔值设置为 false。
  13. 最后,当 retryPromise 解决时,将 response.[[retryPromise]] 设置为 null。
  14. 返回 retryPromise
    注意

    retryPromise 稍后将由用户接受支付请求算法解决,或由用户中止支付请求算法中止更新拒绝。

14.1.1 PaymentValidationErrors 字典

WebIDLdictionary PaymentValidationErrors {
    PayerErrors payer;
    AddressErrors shippingAddress;
    DOMString error;
    object paymentMethod;
};
payer 成员
付款人详细信息相关的验证错误。
shippingAddress 成员
表示 PaymentResponseshippingAddress 的验证错误。
error 成员
关于支付错误的通用描述,用户可以尝试从中恢复。例如,用户可以通过重试支付来恢复。开发者可以选择单独传递 error 成员以提供验证问题的总体概述,或者可以将其与 PaymentValidationErrors 字典的其他成员结合使用。
注意: 错误的国际化
paymentMethod 成员
支付方式特定的错误。

14.1.2 PayerErrors 字典

WebIDLdictionary PayerErrors {
    DOMString email;
    DOMString name;
    DOMString phone;
};

PayerErrors 用于表示一个或多个付款人详细信息的验证错误。

付款人详细信息是指付款人的姓名、付款人的电话号码和付款人的电子邮件中的任何一项。

email 成员
表示付款人的电子邮件存在验证错误。在用户代理的 UI 中,此成员对应于提供 PaymentResponsepayerEmail 属性值的输入字段。
name 成员
表示付款人的姓名存在验证错误。在用户代理的 UI 中,此成员对应于提供 PaymentResponsepayerName 属性值的输入字段。
phone 成员
表示付款人的电话号码存在验证错误。在用户代理的 UI 中,此成员对应于提供 PaymentResponsepayerPhone 属性值的输入字段。

14.2 methodName 属性

用户选择用于完成交易的支付方式支付方式标识符

14.3 details 属性

支付方式生成的object字典,商家可以使用它来处理或验证交易(取决于支付方式)。

注意

14.4 shippingAddress 属性

如果在传递给 PaymentRequest 构造函数的 PaymentOptions 中将 requestShipping 成员设置为 true,则 shippingAddress 将是用户选择的完整且最终的送货地址

14.5 shippingOption 属性

如果在传递给 PaymentRequest 构造函数的 PaymentOptions 中将 requestShipping 成员设置为 true,则 shippingOption 将是所选送货选项的 id 属性。

14.6 payerName 属性

如果在传递给 PaymentRequest 构造函数的 PaymentOptions 中将 requestPayerName 成员设置为 true,则 payerName 将是用户提供的姓名。

14.7 payerEmail 属性

如果在传递给 PaymentRequest 构造函数的 PaymentOptions 中将 requestPayerEmail 成员设置为 true,则 payerEmail 将是用户选择的电子邮件地址。

14.8 payerPhone 属性

如果在传递给 PaymentRequest 构造函数的 PaymentOptions 中将 requestPayerPhone 成员设置为 true,则 payerPhone 将是用户选择的电话号码。

14.9 requestId 属性

生成此支付响应的相应支付请求 id

14.10 complete() 方法

注意

在用户接受支付请求并且 [[acceptPromise]] 已解决后,会调用 complete() 方法。调用 complete() 方法会告知用户代理支付交互已结束(并且应该导致关闭任何剩余的用户界面)。

在支付请求被接受并将 PaymentResponse 返回给调用者之后,但在调用者调用 complete() 之前,支付请求用户界面保持待处理状态。此时,用户界面不应提供取消命令,因为已返回对支付请求的接受。但是,如果出现问题并且开发者从未调用 complete(),则用户界面将被阻止。

因此,实现可以为开发者调用 complete() 设置超时。如果超时到期,则实现将表现得如同调用了不带参数的 complete() 一样。

complete() 方法必须按以下方式操作:

  1. responsethis
  2. 如果 response.[[complete]] 为 true,则返回一个被拒绝的 promise,并带有 "InvalidStateError" DOMException
  3. 如果 response.[[retryPromise]] 不为 null,则返回一个被拒绝的 promise,并带有 "InvalidStateError" DOMException
  4. promise一个新的 promise
  5. serializedData 为将 details.data 序列化为 JSON 字符串的结果。
  6. 如果序列化抛出异常,则返回一个被拒绝的 promise,并带有该异常。
  7. 如果定义 response.methodName 的规范要求:
    1. json 为使用 serializedData 调用 JSONparse() 的结果。
    2. idl 为将 json 转换为由定义 response.methodName 的规范指定的类型的 IDL 值的结果。
    3. 如果转换为 IDL 值抛出异常,则返回一个被拒绝的 promise,并带有该异常。
    4. 如果定义 response.methodName 的规范要求,则验证 idl 的成员。如果成员的值无效,则返回一个被拒绝的 promise,并带有 TypeError
      注意: 恢复机会
  8. response.[[complete]] 设置为 true。
  9. 返回 promise并行执行其余步骤。
  10. 如果在显示用户界面时 document 不再是完全激活状态,或者到达此步骤时不再是,则:
    1. 关闭用户界面。
    2. request支付相关浏览上下文支付请求正在显示布尔值设置为 false。
  11. 否则:
    1. 关闭任何剩余的用户界面。用户代理可以使用值 resultserializedData 来影响用户体验。
    2. request支付相关浏览上下文支付请求正在显示布尔值设置为 false。
    3. 用 undefined 解析 promise

14.11 onpayerdetailchange 属性

允许开发者处理“payerdetailchange”事件。

14.12 内部插槽

PaymentResponse 的实例是使用下表中的内部插槽创建的:

内部插槽 描述 (非规范性)
[[complete]] 如果支付请求已完成(即调用了 complete(),或者存在使响应不再可用的致命错误),则为 true,否则为 false。
[[request]] 实例化此 PaymentResponsePaymentRequest 实例。
[[retryPromise]] Null,或者一个 Promise,当用户接受支付请求时解析,或者如果用户中止支付请求则拒绝。

15. 送货和账单地址

PaymentRequest 接口允许商家向用户请求用于送货和/或账单的实际地址送货地址账单地址都是实际地址

15.1 AddressErrors 字典

WebIDLdictionary AddressErrors {
    DOMString addressLine;
    DOMString city;
    DOMString country;
    DOMString dependentLocality;
    DOMString organization;
    DOMString phone;
    DOMString postalCode;
    DOMString recipient;
    DOMString region;
    DOMString sortingCode;
};

AddressErrors 字典的成员表示实际地址特定部分的验证错误。每个字典成员都有双重功能:首先,它的存在表示地址的特定部分存在验证错误。其次,字符串值允许开发者描述验证错误(以及最终用户如何修复错误)。

注意

开发者需要注意,用户可能无法修复地址的某些部分。因此,他们需要注意不要要求用户修复他们可能无法控制的事情。

addressLine 成员
表示地址行存在验证错误。在用户代理的 UI 中,此成员对应于提供 ContactAddressaddressLine 属性值的输入字段。
city 成员
表示城市存在验证错误。在用户代理的 UI 中,此成员对应于提供 ContactAddresscity 属性值的输入字段。
country 成员
表示国家/地区存在验证错误。在用户代理的 UI 中,此成员对应于提供 ContactAddresscountry 属性值的输入字段。
dependentLocality 成员
表示下属地区存在验证错误。在用户代理的 UI 中,此成员对应于提供 ContactAddressdependentLocality 属性值的输入字段。
organization 成员
表示组织存在验证错误。在用户代理的 UI 中,此成员对应于提供 ContactAddressorganization 属性值的输入字段。
phone 成员
表示电话号码存在验证错误。在用户代理的 UI 中,此成员对应于提供 ContactAddressphone 属性值的输入字段。
postalCode 成员
表示邮政编码存在验证错误。在用户代理的 UI 中,此成员对应于提供 ContactAddresspostalCode 属性值的输入字段。
recipient 成员
表示收件人存在验证错误。在用户代理的 UI 中,此成员对应于提供 ContactAddressaddressLine 属性值的输入字段。
region 成员
表示地区存在验证错误。在用户代理的 UI 中,此成员对应于提供 ContactAddressregion 属性值的输入字段。
sortingCode 成员
分拣码存在验证错误。在用户代理的 UI 中,此成员对应于提供 ContactAddresssortingCode 属性值的输入字段。

16. 权限策略集成

本规范定义了一个由字符串 "payment" 标识的策略控制功能 [permissions-policy]。其默认允许列表'self'

注意

17. 事件

17.1 摘要

本节内容不具约束力。

事件名称 接口 分派时机… 目标
shippingaddresschange PaymentRequestUpdateEvent 用户提供新的送货地址。 PaymentRequest
shippingoptionchange PaymentRequestUpdateEvent 用户选择新的送货选项。 PaymentRequest
payerdetailchange PaymentRequestUpdateEvent 用户更改付款人姓名、付款人电子邮件或付款人电话(请参阅付款人详细信息更改算法)。 PaymentResponse
paymentmethodchange PaymentMethodChangeEvent 用户在支付处理程序中选择不同的支付方式 PaymentRequest

17.2 PaymentMethodChangeEvent 接口

WebIDL[SecureContext, Exposed=Window]
interface PaymentMethodChangeEvent : PaymentRequestUpdateEvent {
    constructor(DOMString type, optional PaymentMethodChangeEventInit eventInitDict = {});
    readonly attribute DOMString methodName;
    readonly attribute object? methodDetails;
};

17.2.1 methodDetails 属性

获取时,返回其初始化时的值。有关更多信息,请参阅 PaymentMethodChangeEventInitmethodDetails 成员。

17.2.2 methodName 属性

获取时,返回其初始化时的值。有关更多信息,请参阅 PaymentMethodChangeEventInitmethodName 成员。

17.2.3 PaymentMethodChangeEventInit 字典

WebIDLdictionary PaymentMethodChangeEventInit : PaymentRequestUpdateEventInit {
    DOMString methodName = "";
    object? methodDetails = null;
};
methodName 成员
一个表示支付方式标识符的字符串。
methodDetails 成员
一个表示来自支付方式的某些数据的对象,或为 null。

17.3 PaymentRequestUpdateEvent 接口

WebIDL[SecureContext, Exposed=Window]
interface PaymentRequestUpdateEvent : Event {
    constructor(DOMString type, optional PaymentRequestUpdateEventInit eventInitDict = {});
    undefined updateWith(Promise<PaymentDetailsUpdate> detailsPromise);
};

PaymentRequestUpdateEvent 使开发者能够响应用户交互来更新支付请求的详细信息。

17.3.1 构造函数

PaymentRequestUpdateEventconstructor(type, eventInitDict) 必须按以下方式操作:

  1. event 为使用 typeeventInitDict 调用 PaymentRequestUpdateEvent构造函数的结果。
  2. event.[[waitForUpdate]] 设置为 false。
  3. 返回 event

17.3.2 updateWith() 方法

注意

带有 detailsPromise 参数的 updateWith() 方法必须按以下方式操作:

  1. eventthis
  2. 如果 eventisTrusted 属性为 false,则抛出一个 "InvalidStateError" DOMException
  3. 如果 event.[[waitForUpdate]] 为 true,则抛出一个 "InvalidStateError" DOMException
  4. 如果 event目标PaymentResponse 的实例,则令 requestevent目标[[request]]
  5. 否则,令 requestevent目标的值。
  6. 断言requestPaymentRequest 的实例。
  7. 如果 request.[[state]] 不是 "interactive",则抛出一个 "InvalidStateError" DOMException
  8. 如果 request.[[updating]] 为 true,则抛出一个 "InvalidStateError" DOMException
  9. 设置 event停止传播标志停止立即传播标志
  10. event.[[waitForUpdate]] 设置为 true。
  11. pmi 为 null。
  12. 如果 event 具有 methodName 属性,则将 pmi 设置为 methodName 属性的值。
  13. 使用 detailsPromiserequestpmi 运行更新 PaymentRequest 详细信息算法

17.3.3 内部插槽

PaymentRequestUpdateEvent 的实例是使用下表中的内部插槽创建的:

内部插槽 描述 (非规范性)
[[waitForUpdate]] 一个布尔值,指示由 updateWith() 启动的更新当前是否正在进行中。

17.3.4 PaymentRequestUpdateEventInit 字典

WebIDLdictionary PaymentRequestUpdateEventInit : EventInit {};

18. 算法

PaymentRequest 对象的内部插槽 [[state]] 设置为“interactive”时,用户代理将根据用户交互触发以下算法。

18.1 “可以付款”算法

“可以付款”算法检查用户代理是否支持使用构建 PaymentRequest 时所用的付款方式进行付款。

  1. request 为调用该方法的 PaymentRequest 对象。
  2. 如果 request.[[state]] 不是“created”,则返回一个被拒绝的 promise,并附带一个“InvalidStateErrorDOMException
  3. 可选地,由顶级浏览上下文自行决定,返回一个被拒绝的 promise,并附带一个“NotAllowedErrorDOMException
    注意

    这允许用户代理应用启发式方法来检测和防止滥用调用方法进行指纹识别,例如创建具有各种受支持付款方式PaymentRequest 对象,并相继对它们触发“可以付款”算法。例如,用户代理可能会根据顶级浏览上下文或进行这些调用的时间段来限制可以进行的成功调用次数。

  4. hasHandlerPromise一个新的 promise
  5. 返回 hasHandlerPromise,并并行执行其余步骤。
  6. 对于 request.[[serializedMethodData]] 中的每个 paymentMethod 元组:
    1. identifierpaymentMethod 元组中的第一个元素。
    2. 如果用户代理具有支持处理 identifier 付款请求的付款处理程序,则使用 true 解析 hasHandlerPromise 并终止此算法。
  7. 使用 false 解析 hasHandlerPromise

18.2 送货地址更改算法

当用户提供新的送货地址时,会运行送货地址更改算法。它必须运行以下步骤:

  1. request 为用户正在与之交互的 PaymentRequest 对象。
  2. 用户交互任务源排队一个任务以运行以下步骤:
    1. 注意:收件人信息的隐私

      redactList 限制了 API 与商家共享的关于收件人的个人信息量。

      对于商家而言,生成的 ContactAddress 对象提供了足够的信息(例如,用于计算运费),但在大多数情况下,不足以实际定位和唯一识别收件人。

      不幸的是,即使有 redactList,也无法保证收件人的匿名性。这是因为在某些国家/地区,邮政编码非常精细,可以唯一识别收件人。

    2. redactList 为空列表。将 redactList 设置为 « "organization", "phone", "recipient", "addressLine" »。
    3. address 为使用 redactList 运行从用户提供的输入创建联系人地址的步骤的结果。
    4. request.shippingAddress 设置为 address
    5. 使用 request 和 "shippingaddresschange" 运行PaymentRequest 更新算法

18.3 送货选项更改算法

当用户选择新的送货选项时,会运行送货选项更改算法。它必须运行以下步骤:

  1. request 为用户正在与之交互的 PaymentRequest 对象。
  2. 用户交互任务源排队一个任务以运行以下步骤:
    1. request 上的 shippingOption 属性设置为用户提供的 PaymentShippingOptionid 字符串。
    2. 使用 request 和 "shippingoptionchange" 运行PaymentRequest 更新算法

18.4 支付方式更改算法

当用户使用 methodDetails(一个字典object 或 null)和 methodName(一个表示用户正在与之交互的支付处理程序支付方式标识符的 DOMString)更改支付方式时,支付处理程序 可以运行支付方式更改算法

注意:paymentmethodchange 事件共享的信息的隐私

当用户选择或更改支付方式(例如信用卡)时,PaymentMethodChangeEvent 包含经过编辑的账单地址信息,用于执行税务计算。经过编辑的属性包括但不限于地址行下属地区组织电话号码收件人

  1. request 为用户正在与之交互的 PaymentRequest 对象。
  2. 用户交互任务源排队一个任务以运行以下步骤:
    1. 断言request.[[updating]] 为 false。一次只能进行一次更新。
    2. 断言request.[[state]] 为 "interactive"。
    3. 使用 PaymentMethodChangeEventrequest触发一个名为 "paymentmethodchange" 的事件,其 methodName 属性初始化为 methodName,其 methodDetails 属性初始化为 methodDetails

18.5 PaymentRequest 更新算法

PaymentRequest 更新算法由上述其他算法运行,以触发一个事件,指示用户已对名为 requestPaymentRequest 进行了更改,事件名称为 name

  1. 断言request.[[updating]] 为 false。一次只能进行一次更新。
  2. 断言request.[[state]] 为 "interactive"。
  3. event 为使用 PaymentRequestUpdateEvent 接口创建事件的结果。
  4. eventtype 属性初始化为 name
  5. request分派 event
  6. 如果 event.[[waitForUpdate]] 为 true,则禁用用户界面中可能导致触发另一个更新事件的任何部分。
  7. 否则,将 event.[[waitForUpdate]] 设置为 true。

18.6 付款人详细信息更改算法

当用户在用户界面中更改付款人姓名付款人电子邮件付款人电话时,用户代理必须运行付款人详细信息更改算法

  1. request 为用户正在与之交互的 PaymentRequest 对象。
  2. 如果 request.[[response]] 为 null,则返回。
  3. responserequest.[[response]]
  4. 用户交互任务源排队一个任务以运行以下步骤:
    1. 断言request.[[updating]] 为 false。
    2. 断言request.[[state]] 为 "interactive"。
    3. optionsrequest.[[options]]
    4. 如果付款人姓名已更改且 options.requestPayerName 为 true:
      1. response.payerName 属性设置为 付款人姓名
    5. 如果付款人电子邮件已更改且 options.requestPayerEmail 为 true:
      1. response.payerEmail 设置为 付款人电子邮件
    6. 如果付款人电话已更改且 options.requestPayerPhone 为 true:
      1. response.payerPhone 设置为 付款人电话
    7. event 为使用 PaymentRequestUpdateEvent 创建事件的结果。
    8. eventtype 属性初始化为 "payerdetailchange"。
    9. response分派 event
    10. 如果 event.[[waitForUpdate]] 为 true,则禁用用户界面中可能导致再次触发付款人详细信息更改的任何部分。
    11. 否则,将 event.[[waitForUpdate]] 设置为 true。

18.7 用户接受支付请求算法

当用户接受支付请求并确认他们想要支付时,会运行用户接受支付请求算法。它必须用户交互任务源排队一个任务以执行以下步骤:

  1. request 为用户正在与之交互的 PaymentRequest 对象。
  2. 如果 request.[[updating]] 为 true,则终止此算法并且不执行任何进一步操作。用户代理用户界面应该确保这种情况永远不会发生。
  3. 如果 request.[[state]] 不是“interactive”,则终止此算法并且不执行任何进一步操作。用户代理用户界面应该确保这种情况永远不会发生。
  4. 如果 request.[[options]]requestShipping 值为 true,那么如果 requestshippingAddress 属性为 null,或者如果 requestshippingOption 属性为 null,则终止此算法并且不执行任何进一步操作。用户代理应该确保这种情况永远不会发生。
  5. 如果 request.[[response]] 不为 null,则令 isRetry 为 true,否则为 false。
  6. 如果 isRetry 为 true,则令 responserequest.[[response]],否则为一个新的 PaymentResponse
  7. 如果 isRetry 为 false,则初始化新创建的 response
    1. response.[[request]] 设置为 request
    2. response.[[retryPromise]] 设置为 null。
    3. response.[[complete]] 设置为 false。
    4. responserequestId 属性值设置为 request.[[details]].id 的值。
    5. request.[[response]] 设置为 response
  8. handlerrequest.[[handler]]
  9. responsemethodName 属性值设置为 handler支付方式标识符
  10. responsedetails 属性值设置为运行 handler响应支付请求的步骤所产生的对象。
  11. 如果 request.[[options]]requestShipping 值为 false,则将 responseshippingAddress 属性值设置为 null。否则:
    1. shippingAddress从用户提供的输入创建联系人地址的结果。
    2. responseshippingAddress 属性值设置为 shippingAddress
    3. requestshippingAddress 属性值设置为 shippingAddress
  12. 如果 request.[[options]]requestShipping 值为 true,则将 responseshippingOption 属性设置为 requestshippingOption 属性的值。否则,将其设置为 null。
  13. 如果 request.[[options]]requestPayerName 值为 true,则将 responsepayerName 属性设置为用户提供的付款人姓名,如果未提供则为 null。否则,将其设置为 null。
  14. 如果 request.[[options]]requestPayerEmail 值为 true,则将 responsepayerEmail 属性设置为用户提供的付款人电子邮件地址,如果未提供则为 null。否则,将其设置为 null。
  15. 如果 request.[[options]]requestPayerPhone 值为 true,则将 responsepayerPhone 属性设置为用户提供的付款人电话号码,如果未提供则为 null。设置 payerPhone 值时,用户代理应该将电话号码格式化以符合 [E.164]。
  16. request.[[state]] 设置为“closed”。
  17. 如果 isRetry 为 true,则使用 undefined 解析 response.[[retryPromise]]。否则,使用 response 解析 request.[[acceptPromise]]

18.8 用户中止支付请求算法

当用户通过当前交互式用户界面中止支付请求时,会运行用户中止支付请求算法。它必须用户交互任务源排队一个任务以执行以下步骤:

  1. request 为用户正在与之交互的 PaymentRequest 对象。
  2. 如果 request.[[state]] 不是“interactive”,则终止此算法并且不执行任何进一步操作。用户代理用户界面应该确保这种情况永远不会发生。
  3. request.[[state]] 设置为“closed”。
  4. request与支付相关的浏览上下文支付请求正在显示布尔值设置为 false。
  5. error 为一个“AbortErrorDOMException
  6. responserequest.[[response]]
  7. 如果 response 不为 null:
    1. response.[[complete]] 设置为 true。
    2. 断言response.[[retryPromise]] 不为 null。
    3. 使用 error 拒绝 response.[[retryPromise]]
  8. 否则,使用 error 拒绝 request.[[acceptPromise]]
  9. 中止当前用户交互并关闭任何剩余的用户界面。

18.9 更新 PaymentRequest 的详细信息算法

更新 PaymentRequest 的详细信息算法接受一个 PaymentDetailsUpdate detailsPromise、一个 PaymentRequest request 和一个 pmi(一个 DOMString 或 null,即支付方式标识符)。这些步骤取决于 detailsPromise 的解决情况。如果 detailsPromise 永远不解决,则支付请求将被阻塞。用户代理应该为用户提供中止支付请求的方法。如果 detailsPromise 在合理的时间内没有解决,实现可以选择为待处理的更新实现超时。

如果发生超时、用户手动中止或支付处理程序决定中止此特定支付,用户代理必须运行用户中止支付请求算法

  1. request.[[updating]] 设置为 true。
  2. 并行地,禁用允许用户接受支付请求的用户界面。这是为了确保在用户界面更新任何新详细信息之前不接受支付。
  3. detailsPromise 被拒绝时
    1. 使用 request 和一个“AbortErrorDOMException 中止更新
  4. detailsPromise 被满足且值为 value 时:
    1. details 为将 value 转换PaymentDetailsUpdate 字典的结果。如果此操作抛出异常,则使用 request 和抛出的异常中止更新
    2. serializedModifierData 为一个空列表。
    3. selectedShippingOption 为 null。
    4. shippingOptions 为一个空的 sequence<PaymentShippingOption>。
    5. 验证并规范化详细信息:
      1. 如果 detailstotal 成员存在,则:
        1. 检查并规范化总金额 details.total.amount。如果抛出异常,则使用 request 和该异常中止更新
      2. 如果 detailsdisplayItems 成员存在,则对于 details.displayItems 中的每个 item
        1. 检查并规范化金额 item.amount。如果抛出异常,则使用 request 和该异常中止更新
      3. 如果 detailsshippingOptions 成员存在,并且 request.[[options]].requestShipping 为 true,则:
        1. seenIDs 为一个空集合。
        2. 对于 details.shippingOptions 中的每个 option
          1. 检查并规范化金额 option.amount。如果抛出异常,则使用 request 和该异常中止更新
          2. 如果 seenIDs[option.{{PaymentShippingOption/id}}] 存在,则使用 request 和一个 TypeError 中止更新
          3. option.id 附加到 seenIDs
          4. option 附加到 shippingOptions
          5. 如果 option.selected 为 true,则将 selectedShippingOption 设置为 option.id
      4. 如果 detailsmodifiers 成员存在,则:
        1. modifiers 为序列 details.modifiers
        2. serializedModifierData 为一个空列表。
        3. 对于 modifiers 中的每个 PaymentDetailsModifier modifier
          1. 使用 modifier.supportedMethods 运行验证支付方式标识符的步骤。如果返回 false,则使用 request 和一个 RangeError 异常中止更新。可选地,通知开发者支付方式标识符无效。
          2. 如果 modifiertotal 成员存在,则:
            1. 检查并规范化总金额 modifier.total.amount。如果抛出异常,则使用 request 和该异常中止更新
          3. 如果 modifieradditionalDisplayItems 成员存在,则对于 modifier.additionalDisplayItems 中的每个 PaymentItem item
            1. 检查并规范化金额 item.amount。如果抛出异常,则使用 request 和该异常中止更新
          4. 如果 modifierdata 成员缺失,则令 serializedData 为 null。否则,令 serializedData 为将 modifier.data 序列化为 JSON 字符串的结果。如果抛出异常,则使用 request 和该异常中止更新
          5. serializedData 添加到 serializedModifierData
          6. 如果 modifierdata 成员存在,则移除它。
    6. 如果 paymentMethodErrors 成员存在且 identifier 不为 null:
      1. 如果定义 pmi 的规范要求,则将 paymentMethodErrors 转换为 IDL 值。
      2. 如果转换导致异常 error,则使用 error 中止更新
      3. 支付处理程序应该paymentMethodErrors 的每个相关错误字段显示错误。
    7. 使用新详细信息更新 PaymentRequest
      1. 如果 detailstotal 成员存在,则:
        1. request.[[details]].total 设置为 details.total
      2. 如果 detailsdisplayItems 成员存在,则:
        1. request.[[details]].displayItems 设置为 details.displayItems
      3. 如果 detailsshippingOptions 成员存在,并且 request.[[options]].requestShipping 为 true,则:
        1. request.[[details]].shippingOptions 设置为 shippingOptions
        2. requestshippingOption 属性的值设置为 selectedShippingOption
      4. 如果 detailsmodifiers 成员存在,则:
        1. request.[[details]].modifiers 设置为 details.modifiers
        2. request.[[serializedModifierData]] 设置为 serializedModifierData
      5. 如果 request.[[options]].requestShipping 为 true,并且 request.[[details]].shippingOptions 为空,则开发者已表示对于当前选择的送货地址(由 requestshippingAddress 给出)没有有效的送货选项。

        在这种情况下,用户代理应该显示一个错误来指示这一点,并且可以指示当前选择的送货地址在某种程度上无效。用户代理应该使用 detailserror 成员(如果存在)来提供更多关于为什么该地址没有有效送货选项的信息。

        此外,如果 details["shippingAddressErrors"] 成员存在,用户代理应该为送货地址的每个错误字段专门显示一个错误。这是通过将 AddressErrors 的每个存在的成员与所显示用户界面中的相应输入字段进行匹配来完成的。

        类似地,如果 details["payerErrors"] 成员存在且 request.[[options]]requestPayerNamerequestPayerEmailrequestPayerPhone 为 true,则为每个错误字段专门显示一个错误。

        同样,如果 details.paymentMethodErrors 存在,则为特定支付方式的每个错误输入字段专门显示错误。

  5. request.[[updating]] 设置为 false。
  6. 根据 request 中任何已更改的值更新用户界面。重新启用在此算法运行之前禁用的用户界面元素。

18.9.1 中止更新

使用 PaymentRequest request异常 exception中止更新

  1. 可选地,在通知用户发生错误时向用户显示错误消息。
  2. 中止当前用户交互并关闭任何剩余的用户界面。
  3. 用户交互任务源排队一个任务以执行以下步骤:
    1. request与支付相关的浏览上下文支付请求正在显示布尔值设置为 false。
    2. request.[[state]] 设置为“closed”。
    3. responserequest.[[response]]
    4. 如果 response 不为 null,则:
      1. response.[[complete]] 设置为 true。
      2. 断言response.[[retryPromise]] 不为 null。
      3. 使用 exception 拒绝 response.[[retryPromise]]
    5. 否则,使用 exception 拒绝 request.[[acceptPromise]]
    6. request.[[updating]] 设置为 false。
  4. 中止算法。
注意

当更新支付请求时发生致命错误(例如提供的 detailsPromise 被拒绝,或其满足值包含无效数据)时,会运行中止更新。这可能会使支付请求处于不一致状态,因为开发者尚未成功处理更改事件。

因此,PaymentRequest 会进入“closed”状态。错误通过拒绝 [[acceptPromise]](即 show() 返回的 promise)向开发者发出信号。

类似地,在 retry() 期间发生中止更新会导致 [[retryPromise]] 被拒绝,并且相应的 PaymentResponse[[complete]] 内部插槽将被设置为 true(即,它不能再使用)。

19. 隐私和安全注意事项

19.1 使用 show() 方法的用户保护

本节内容不具约束力。

为帮助确保用户不会无意中与某个来源共享敏感凭据,此 API 要求在相关 Window 具有瞬时激活(例如,通过单击或按压)时调用 PaymentRequest 的 show() 方法。

为避免混乱的用户体验,本规范限制用户代理通过 show() 方法一次仅显示一个。此外,用户代理可以限制页面调用 show() 的速率。

19.2 安全上下文

本节内容不具约束力。

本规范中定义的 API 仅在安全上下文中公开——另请参阅 安全上下文规范了解更多详细信息。实际上,这意味着此 API 仅通过 HTTPS 可用。这是为了限制支付方式数据(例如信用卡号)以明文形式发送的可能性。

19.3 跨源支付请求

本节内容不具约束力。

商家和其他收款人通常通过 iframe 将结账和其他电子商务活动委托给支付服务提供商。此 API 通过 [HTML] 的 allow 属性支持收款人授权的跨源 iframe。

支付处理程序可以访问托管 iframe 的源以及 iframe 内容的源(PaymentRequest 在此处发起)。

19.4 数据字段加密

本节内容不具约束力。

PaymentRequest API 不直接支持数据字段的加密。各个支付方式可以选择包含对加密数据的支持,但并非强制所有支付方式都支持此功能。

19.5 用户代理如何匹配支付处理程序

本节内容不具约束力。

出于安全原因,用户代理可以将(在 show()canMakePayment() 中)匹配限制为与 URL 支付方式标识符具有相同来源支付处理程序

19.6 数据使用

支付方式所有者制定关于如何使用为该支付方式收集的用户数据的隐私政策。Payment Request API 明确规定数据将用于完成交易的目的,并且与此 API 相关的用户体验传达了这一意图。收款人有责任确保任何数据使用都符合支付方式政策。对于超出完成交易范围的任何允许使用,收款人应向用户清楚地传达该使用情况。

19.7 公开用户信息

用户代理不得在未经用户同意的情况下与开发者共享有关用户的信息(例如送货地址)。

特别是,PaymentMethodDatadataPaymentResponsedetails 成员允许任意交换数据。鉴于现有支付方式使用的数据模型范围广泛,在此 API 中规定数据细节会限制其有用性。details 成员携带来自支付处理程序的数据,无论是基于 Web 的(由 支付处理程序 API 定义)还是专有的。用户代理不得支持支付处理程序,除非它们包含足够的用户同意机制(例如交易各方的知情权和表明共享数据意图的机制)。

用户代理不得出于促进交易完成以外的任何目的共享 displayItems 成员或 additionalDisplayItems 成员的值。

PaymentMethodChangeEvent 使收款人能够根据所选支付方式的特定信息更新显示的总额。例如,与所选支付方式关联的账单地址可能会影响税款计算(例如增值税),并且希望用户界面在付款人完成交易之前准确显示总额。同时,希望在完成付款之前尽可能少地共享信息。因此,当支付方式定义用户更改支付方式时的步骤时,重要的是尽量减少通过 PaymentMethodChangeEventmethodDetails 属性共享的数据。最小化共享数据的要求和方法可能因支付方式而异,并且可能包括:

在共享隐私敏感信息可能对用户不明显的情况下(例如,当更改支付方式时),建议用户代理告知用户正在与商家共享哪些确切信息。

19.8 canMakePayment() 保护措施

canMakePayment() 方法为不同的支付方式提供功能检测。如果将来有大量支付方式可用,它可能会成为一个指纹识别向量。用户代理应保护用户免受该方法的滥用。例如,用户代理可以通过以下方式减少用户指纹识别:

对于速率限制,用户代理可能会查看来自以下位置的重复调用:

这些速率限制技术旨在增加与重复调用相关的成本,无论是管理多个可注册域的成本,还是打开多个窗口(选项卡或弹出窗口)的用户体验摩擦。

19.9 用户激活要求

如果用户代理不要求用户激活作为 show() 方法的一部分,则应考虑一些额外的安全缓解措施。不要求用户激活会增加垃圾邮件和点击劫持攻击的风险,因为它允许在用户没有立即与页面交互的情况下启动支付请求 UI。

为了缓解垃圾邮件,用户代理可以决定在某个阈值之后强制执行用户激活要求,例如在用户已经在当前页面上看到没有用户激活的支付请求 UI 之后。为了缓解点击劫持攻击,用户代理可以实现一个时间阈值,在该阈值内,在显示对话框后立即忽略点击。

show() 的步骤 6 中存在另一个相关的缓解措施,其中文档必须可见才能启动用户交互。

20. 无障碍注意事项

本节内容不具约束力。

对于 Payment Request API 面向用户的方面,实现通过表单控件和其他输入方式与平台无障碍 API 集成。此外,为了提高总计、送货地址和联系信息的可理解性,实现会根据系统约定格式化数据。

21. 依赖项

本规范依赖于其他几个底层规范。

ECMAScript
术语 内部插槽 定义在 [ECMASCRIPT] 中。

22. 一致性

除了标记为非规范性的章节外,本规范中的所有创作指南、图表、示例和注释都是非规范性的。本规范中的其他所有内容都是规范性的。

本文档中的关键词 可以必须不得可选建议应该不应 按照 BCP 14 [RFC2119] [RFC8174] 中的描述进行解释,当且仅当它们以全大写形式出现时,如此处所示。

只有一类产品可以声称符合本规范:用户代理

注意

尽管本规范主要针对 Web 浏览器,但其他软件也有可能以符合规范的方式实现本规范。

用户代理可以以任何期望的方式实现本规范中给出的算法,只要最终结果与通过规范算法获得的结果无法区分即可。

用户代理可以对其他不受约束的输入施加特定于实现的限制,例如,为了防止拒绝服务攻击、防止内存耗尽或解决特定于平台的限制。当输入超出特定于实现的限制时,用户代理必须抛出,或者在 promise 的上下文中,拒绝并抛出 TypeError,并可选地通知开发者特定输入如何超出特定于实现的限制。

A. IDL 索引

WebIDL[SecureContext, Exposed=Window]
interface PaymentRequest : EventTarget {
  constructor(
    sequence<PaymentMethodData> methodData,
    PaymentDetailsInit details,
    optional PaymentOptions options = {}
  );
  [NewObject]
  Promise<PaymentResponse> show(optional Promise<PaymentDetailsUpdate> detailsPromise);
  [NewObject]
  Promise<undefined> abort();
  [NewObject]
  Promise<boolean> canMakePayment();

  readonly attribute DOMString id;
  readonly attribute ContactAddress? shippingAddress;
  readonly attribute DOMString? shippingOption;
  readonly attribute PaymentShippingType? shippingType;

  attribute EventHandler onshippingaddresschange;
  attribute EventHandler onshippingoptionchange;
  attribute EventHandler onpaymentmethodchange;
};

dictionary PaymentMethodData {
  required DOMString supportedMethods;
  object data;
};

dictionary PaymentCurrencyAmount {
  required DOMString currency;
  required DOMString value;
};

dictionary PaymentDetailsBase {
  sequence<PaymentItem> displayItems;
  sequence<PaymentShippingOption> shippingOptions;
  sequence<PaymentDetailsModifier> modifiers;
};

dictionary PaymentDetailsInit : PaymentDetailsBase {
  DOMString id;
  required PaymentItem total;
};

dictionary PaymentDetailsUpdate : PaymentDetailsBase {
  DOMString error;
  PaymentItem total;
  AddressErrors shippingAddressErrors;
  PayerErrors payerErrors;
  object paymentMethodErrors;
};

dictionary PaymentDetailsModifier {
  required DOMString supportedMethods;
  PaymentItem total;
  sequence<PaymentItem> additionalDisplayItems;
  object data;
};

enum PaymentShippingType {
  "shipping",
  "delivery",
  "pickup"
};

dictionary PaymentOptions {
  boolean requestPayerName = false;
  boolean requestBillingAddress = false;
  boolean requestPayerEmail = false;
  boolean requestPayerPhone = false;
  boolean requestShipping = false;
  PaymentShippingType shippingType = "shipping";
};

dictionary PaymentItem {
  required DOMString label;
  required PaymentCurrencyAmount amount;
  boolean pending = false;
};

dictionary PaymentCompleteDetails {
  object? data = null;
};

enum PaymentComplete {
  "fail",
  "success",
  "unknown"
};

dictionary PaymentShippingOption {
  required DOMString id;
  required DOMString label;
  required PaymentCurrencyAmount amount;
  boolean selected = false;
};

[SecureContext, Exposed=Window]
interface PaymentResponse : EventTarget  {
  [Default] object toJSON();

  readonly attribute DOMString requestId;
  readonly attribute DOMString methodName;
  readonly attribute object details;
  readonly attribute ContactAddress? shippingAddress;
  readonly attribute DOMString? shippingOption;
  readonly attribute DOMString? payerName;
  readonly attribute DOMString? payerEmail;
  readonly attribute DOMString? payerPhone;

  [NewObject]
  Promise<undefined> complete(
    optional PaymentComplete result = "unknown",
    optional PaymentCompleteDetails details = {}
  );
  [NewObject]
  Promise<undefined> retry(optional PaymentValidationErrors errorFields = {});

  attribute EventHandler onpayerdetailchange;
};

dictionary PaymentValidationErrors {
  PayerErrors payer;
  AddressErrors shippingAddress;
  DOMString error;
  object paymentMethod;
};

dictionary PayerErrors {
  DOMString email;
  DOMString name;
  DOMString phone;
};

dictionary AddressErrors {
  DOMString addressLine;
  DOMString city;
  DOMString country;
  DOMString dependentLocality;
  DOMString organization;
  DOMString phone;
  DOMString postalCode;
  DOMString recipient;
  DOMString region;
  DOMString sortingCode;
};

[SecureContext, Exposed=Window]
interface PaymentMethodChangeEvent : PaymentRequestUpdateEvent {
  constructor(DOMString type, optional PaymentMethodChangeEventInit eventInitDict = {});
  readonly attribute DOMString methodName;
  readonly attribute object? methodDetails;
};

dictionary PaymentMethodChangeEventInit : PaymentRequestUpdateEventInit {
  DOMString methodName = "";
  object? methodDetails = null;
};

[SecureContext, Exposed=Window]
interface PaymentRequestUpdateEvent : Event {
  constructor(DOMString type, optional PaymentRequestUpdateEventInit eventInitDict = {});
  undefined updateWith(Promise<PaymentDetailsUpdate> detailsPromise);
};

dictionary PaymentRequestUpdateEventInit : EventInit {};

B. 致谢

本规范源自 Web 平台孵化器社区组先前发布的一份报告。

C. 变更日志

从 CR2 到现在的变更:

CR1 和 CR2 之间的变更:

D. 参考文献

D.1 规范性参考文献

[contact-picker]
联系人选择器 API。Peter Beverloo。 W3C。2024 年 7 月 8 日。W3C 工作草案。URL:https://www.w3.org/TR/contact-picker/
[dom]
DOM 标准。Anne van Kesteren。WHATWG。 现行标准。URL:https://dom.spec.whatwg.org/
[E.164]
国际公共电信编号计划。ITU-T。2010 年 11 月。 建议。URL:https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-E.164-201011-I!!PDF-E&type=items
[ecma-402]
ECMAScript 国际化 API 规范。Ecma International。URL:https://tc39.es/ecma402/
[ECMASCRIPT]
ECMAScript 语言规范。 Ecma International。URL:https://tc39.es/ecma262/multipage/
[fetch]
Fetch 标准。Anne van Kesteren。WHATWG。 现行标准。URL:https://fetch.spec.whatwg.org/
[HTML]
HTML 标准。Anne van Kesteren; Domenic Denicola;Dominic Farolino;Ian Hickson;Philip Jägenstedt;Simon Pieters。WHATWG。现行标准。URL:https://html.spec.whatwg.org/multipage/
[infra]
Infra 标准。Anne van Kesteren;Domenic Denicola。WHATWG。现行标准。URL:https://infra.spec.whatwg.org/
[ISO4217]
货币代码 - ISO 4217。ISO。2015 年。国际标准。URL:http://www.iso.org/iso/home/standards/currency_codes.htm
[payment-handler]
支付处理程序 API。Adrian Hope-Bailie;Ian Jacobs;Rouslan Solomakhin;Jinho Bang。W3C。2023 年 1 月 25 日。W3C 工作草案。 URL:https://www.w3.org/TR/payment-handler/
[payment-method-id]
支付方式标识符。 Marcos Caceres。W3C。2022 年 9 月 8 日。W3C 推荐标准。URL:https://www.w3.org/TR/payment-method-id/
[permissions-policy]
权限策略。Ian Clelland。W3C。2025 年 2 月 10 日。W3C 工作草案。URL:https://www.w3.org/TR/permissions-policy-1/
[RFC2119]
用于 RFC 中指示需求级别的关键词。S. Bradner。IETF。1997 年 3 月。最佳当前实践。URL:https://www.rfc-editor.org/rfc/rfc2119
[RFC4122]
通用唯一标识符 (UUID) URN 命名空间。P. Leach;M. Mealling;R. Salz。IETF。2005 年 7 月。建议标准。 URL:https://www.rfc-editor.org/rfc/rfc4122
[RFC8174]
RFC 2119 关键词中大写与小写的歧义性。B. Leiba。IETF。2017 年 5 月。最佳当前实践。URL:https://www.rfc-editor.org/rfc/rfc8174
[url]
URL 标准。Anne van Kesteren。WHATWG。 现行标准。URL:https://url.spec.whatwg.org/
[WEBIDL]
Web IDL 标准。Edgar Chen;Timothy Gu。 WHATWG。现行标准。URL:https://webidl.spec.whatwg.org/

D.2 信息性参考文献

[rfc6454]
Web 源概念。A. Barth。 IETF。2011 年 12 月。建议标准。URL:https://www.rfc-editor.org/rfc/rfc6454
[secure-contexts]
安全上下文。Mike West。W3C。 2023 年 11 月 10 日。CRD。URL:https://www.w3.org/TR/secure-contexts/