如何使基于 Web 的付款应用适应 Web Payments,并为客户提供更好的用户体验。
一旦基于 Web 的支付应用收到付款请求并启动付款交易,服务工作线程就会充当商家与支付应用之间通信的枢纽。本文将介绍支付应用如何使用服务工作线程将付款方式、送货地址或联系信息传递给商家。

通知商家
请务必告知商家以下变更。
付款方式更改
支付应用可以支持多种支付工具,并提供不同的支付方式。
客户 | 付款方式 | 支付方式 |
---|---|---|
A | 信用卡发卡机构 1 | ****1234 |
信用卡发卡机构 1 | ****4242 |
|
X 银行 | ******123 |
|
B | 信用卡发卡机构 2 | ****5678 |
X 银行 | ******456 |
例如,在上表中,客户 A 的基于 Web 的钱包注册了两张信用卡和一个银行账号。在这种情况下,应用正在处理三种付款方式(****1234
、****4242
、******123
)和两种付款方法(信用卡发卡机构 1 和银行 X)。在付款交易中,付款应用可让客户选择一种付款方式,并使用该方式向商家付款。

付款应用可以在发送完整付款响应之前,让商家知道客户选择了哪种付款方式。当商家想要针对特定付款方式品牌开展折扣广告系列时,此功能非常有用。
借助 Payment Handler API,支付应用可以通过服务工作线程向商家发送“支付方式更改”事件,以通知新的支付方式标识符。服务工作线程应使用新的付款方式信息调用 PaymentRequestEvent.changePaymentMethod()
。

支付应用可以传递 methodDetails
对象作为 PaymentRequestEvent.changePaymentMethod()
的可选第二个实参。此对象可以包含商家处理更改事件所需的任意付款方式详细信息。
[付款处理程序] service-worker.js
…
// Received a message from the frontend
self.addEventListener('message', async e => {
let details;
try {
switch (e.data.type) {
…
case 'PAYMENT_METHOD_CHANGED':
const newMethod = e.data.paymentMethod;
const newDetails = e.data.methodDetails;
// Redact or check that no sensitive information is passed in
// `newDetails`.
// Notify the merchant of the payment method change
details =
await payment_request_event.changePaymentMethod(newMethod, newDetails);
…
当商家从 Payment Request API 收到 paymentmethodchange
事件时,可以更新付款详情并使用 PaymentDetailsUpdate
对象进行响应。
[merchant]
request.addEventListener('paymentmethodchange', e => {
if (e.methodName === 'another-pay') {
// Apply $10 discount for example.
const discount = {
label: 'special discount',
amount: {
currency: 'USD',
// The value being string complies the spec
value: '-10.00'
}
};
let total = 0;
details.displayItems.push(discount);
for (let item of details.displayItems) {
total += parseFloat(item.amount.value);
}
// Convert the number back to string
details.total.amount.value = total.toString();
}
// Pass a promise to `updateWith()` and send updated payment details
e.updateWith(details);
});
当商家做出回应时,PaymentRequestEvent.changePaymentMethod()
返回的 promise 将解析为 PaymentRequestDetailsUpdate
对象。
[付款处理程序] service-worker.js
…
// Notify the merchant of the payment method change
details = await payment_request_event.changePaymentMethod(newMethod, newDetails);
// Provided the new payment details,
// send a message back to the frontend to update the UI
postMessage('UPDATE_REQUEST', details);
break;
…
使用该对象更新前端界面。请参阅反映更新后的付款信息。
更改送货地址
付款应用可以向商家提供客户的送货地址,作为付款交易的一部分。
这对商家很有用,因为他们可以将地址收集工作委托给付款应用。此外,由于地址数据将以标准数据格式提供,因此商家可以预期会收到结构一致的送货地址。
此外,客户可以在自己偏好的支付应用中登记地址信息,并将其重复用于不同的商家。

支付应用可以提供界面来修改送货地址,或者为客户在支付交易中选择预先注册的地址信息。 当临时确定送货地址时,支付应用可以告知商家已隐去地址信息。这可为商家带来多重好处:
- 商家可以确定客户是否满足商品配送的地区限制(例如,仅限国内)。
- 商家可以根据送货地址的区域更改送货选项列表(例如,国际普通或快递)。
- 商家可以根据地址应用新的运费,并更新总价。
借助 Payment Handler API,付款应用可以从服务工作线程向商家发送“送货地址变更”事件,以通知新的送货地址。服务工作线程应使用新地址对象调用 PaymentRequestEvent.changeShippingAddress()
。

[付款处理程序] service-worker.js
...
// Received a message from the frontend
self.addEventListener('message', async e => {
let details;
try {
switch (e.data.type) {
…
case 'SHIPPING_ADDRESS_CHANGED':
const newAddress = e.data.shippingAddress;
details =
await payment_request_event.changeShippingAddress(newAddress);
…
关键术语:已遮盖的地址。在这种情况下,向商家提供完整的送货地址是不必要的,并且会给客户的隐私带来风险。商家只会收到确定运费所需的地址信息。具体而言,浏览器会在商家 DOM 中引发 shippingaddresschange
事件之前,从付款应用提供的地址中清除 organization
、phone
、recipient
、addressLine
字段。
商家将从 Payment Request API 收到 shippingaddresschange
事件,以便他们使用更新后的 PaymentDetailsUpdate
进行响应。
[merchant]
request.addEventListener('shippingaddresschange', e => {
// Read the updated shipping address and update the request.
const addr = request.shippingAddress;
const details = getPaymentDetailsFromShippingAddress(addr);
// `updateWith()` sends back updated payment details
e.updateWith(details);
});
当商家做出回应时,返回的 promise PaymentRequestEvent.changeShippingAddress()
将解析为 PaymentRequestDetailsUpdate
对象。
[付款处理程序] service-worker.js
…
// Notify the merchant of the shipping address change
details = await payment_request_event.changeShippingAddress(newAddress);
// Provided the new payment details,
// send a message back to the frontend to update the UI
postMessage('UPDATE_REQUEST', details);
break;
…
使用该对象更新前端界面。请参阅反映更新后的付款信息。
通知商家送货选项变更
配送选项是指商家用于将所购商品配送给客户的配送方式。常见的配送选项包括:
- 免运费
- 极速配送
- 全球送货
- 高级国际配送
每种方法都有自己的成本。通常,速度更快的方法和选项价格更高。
使用 Payment Request API 的商家可以将此选择委托给付款应用。付款应用可以使用这些信息来构建界面,并让客户选择配送选项。

商家在 Payment Request API 中指定的配送选项列表会作为 PaymentRequestEvent
的属性传播到支付应用的服务工作线程。
[merchant]
const request = new PaymentRequest([{
supportedMethods: 'https://bobbucks.dev/pay',
data: { transactionId: '****' }
}], {
displayItems: [{
label: 'Anvil L/S Crew Neck - Grey M x1',
amount: { currency: 'USD', value: '22.15' }
}],
shippingOptions: [{
id: 'standard',
label: 'Standard',
amount: { value: '0.00', currency: 'USD' },
selected: true
}, {
id: 'express',
label: 'Express',
amount: { value: '5.00', currency: 'USD' }
}],
total: {
label: 'Total due',
amount: { currency: 'USD', value : '22.15' }
}
}, { requestShipping: true });
付款应用可以告知商家客户选择了哪种配送选项。这对商家和客户都很重要,因为更改配送选项也会更改总价。商家需要了解最新价格,以便日后进行付款验证,客户也需要了解价格变动。
借助 Payment Handler API,付款应用可以从服务工作线程向商家发送“配送选项更改”事件。服务工作线程应使用新的配送选项 ID 调用 PaymentRequestEvent.changeShippingOption()
。

[付款处理程序] service-worker.js
…
// Received a message from the frontend
self.addEventListener('message', async e => {
let details;
try {
switch (e.data.type) {
…
case 'SHIPPING_OPTION_CHANGED':
const newOption = e.data.shippingOptionId;
details =
await payment_request_event.changeShippingOption(newOption);
…
商家将从 Payment Request API 收到 shippingoptionchange
事件。商家应使用该信息更新总价,然后使用更新后的 PaymentDetailsUpdate
进行响应。
[merchant]
request.addEventListener('shippingoptionchange', e => {
// selected shipping option
const shippingOption = request.shippingOption;
const newTotal = {
currency: 'USD',
label: 'Total due',
value: calculateNewTotal(shippingOption),
};
// `updateWith()` sends back updated payment details
e.updateWith({ total: newTotal });
});
当商家做出回应时,PaymentRequestEvent.changeShippingOption()
返回的 promise 将解析为 PaymentRequestDetailsUpdate
对象。
[付款处理程序] service-worker.js
…
// Notify the merchant of the shipping option change
details = await payment_request_event.changeShippingOption(newOption);
// Provided the new payment details,
// send a message back to the frontend to update the UI
postMessage('UPDATE_REQUEST', details);
break;
…
使用该对象更新前端界面。请参阅反映更新后的付款信息。
反映更新后的付款信息
商家完成付款详情更新后,从 .changePaymentMethod()
、.changeShippingAddress()
和 .changeShippingOption()
返回的 promise 将解析为通用 PaymentRequestDetailsUpdate
对象。支付处理程序可以使用该结果向界面反映更新后的总价和配送选项。
商家可能会因多种原因而返回错误:
- 付款方式不可接受。
- 送货地址不在其支持的区域内。
- 送货地址包含无效信息。
- 所提供的送货地址或某些其他原因导致无法选择相应配送选项。
使用以下属性反映错误状态:
error
:人类可读的错误字符串。这是向客户显示的最佳字符串。shippingAddressErrors
:AddressErrors
对象,其中包含每个地址属性的详细错误字符串。如果您想打开一个表单,让客户修改其地址,并且需要直接向客户指出无效字段,那么此方法非常有用。paymentMethodErrors
:特定于付款方式的错误对象。您可以要求商家提供结构化错误,但 Web Payments 规范作者建议将其保留为简单的字符串。
示例代码
您在本文档中看到的大部分示例代码都摘自一个示例应用。
如需试用,请执行以下操作:
- 前往 https://paymentrequest-demo.glitch.me/。
- 前往页面底部。
- 按 Add a payment button。
- 在付款方式标识符字段中输入
https://paymenthandler-demo.glitch.me
。 - 按相应字段旁边的付款按钮。