使用 Service Worker 处理可选支付信息

如何使您的基于 Web 的支付应用适配 Web Payments 并为客户提供更好的用户体验。

一旦基于 Web 的支付应用收到付款请求并启动付款交易,Service Worker 将充当商家和支付应用之间通信的中心。这篇文章解释了支付应用如何使用 Service Worker 将关于支付方式、送货地址或联系方式的信息传递给商家。

Handling optional payment information with a service worker
使用 Service Worker 处理可选支付信息

通知商家支付方式变更

支付应用可以支持具有不同支付方式的多种支付工具。

客户 支付方式 支付工具
A 信用卡发行商 1 ****1234
信用卡发行商 1 ****4242
银行 X ******123
B 信用卡发行商 2 ****5678
银行 X ******456

示例:在上表中,客户 A 的基于 Web 的钱包注册了两张信用卡和一个银行账户。在这种情况下,该应用正在处理三个支付工具 (****1234, ****4242, ******123) 和两种支付方式(信用卡发行商 1 和银行 X)。在支付交易中,支付应用可以让客户选择其中一个支付工具并用它向商家付款。

Payment method picker UI
支付方式选择器 UI

支付应用可以在发送完整的付款响应之前让商家知道客户选择了哪种支付方式。当商家想要针对特定支付方式品牌开展折扣活动时,这非常有用。

通过 Payment Handler API,支付应用可以通过 Service Worker 向商家发送“支付方式变更”事件,以通知新的支付方式标识符。Service Worker 应使用新的支付方式信息调用 PaymentRequestEvent.changePaymentMethod()

Inform the merchant of a payment method change
通知商家支付方式变更

支付应用可以将 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 对象进行响应。

[商家]

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;

使用该对象更新前端的 UI。请参阅反映更新后的支付详细信息

通知商家送货地址变更

支付应用可以将客户的送货地址作为支付交易的一部分提供给商家。

这对商家很有用,因为他们可以将地址收集委托给支付应用。而且,由于地址数据将以 标准数据格式提供,商家可以期望收到结构一致的送货地址。

此外,客户可以使用他们首选的支付应用注册他们的地址信息,并在不同的商家处重复使用。

Shipping address picker UI
送货地址选择器 UI

支付应用可以提供一个 UI,用于在支付交易中编辑送货地址或为客户选择预先注册的地址信息。当临时确定送货地址时,支付应用可以让商家知道经过编辑的地址信息。这为商家提供了多项好处

  • 商家可以确定客户是否满足运送商品的区域限制(例如,仅限国内)。
  • 商家可以根据送货地址的区域更改送货选项列表(例如,国际普通或快递)。
  • 商家可以根据地址应用新的运费并更新总价。

通过 Payment Handler API,支付应用可以从 Service Worker 向商家发送“送货地址变更”事件,以通知新的送货地址。Service Worker 应使用新的地址对象调用 PaymentRequestEvent.changeShippingAddress()

Inform the merchant of a shipping address change
通知商家送货地址变更

[支付处理程序] 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);
      

商家将从 Payment Request API 收到 shippingaddresschange 事件,以便他们可以使用更新后的 PaymentDetailsUpdate 进行响应。

[商家]

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);
});

当商家响应时,PaymentRequestEvent.changeShippingAddress() 返回的 Promise 将会使用 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;

使用该对象更新前端的 UI。请参阅反映更新后的支付详细信息

通知商家送货选项变更

送货选项是商家用来将购买的商品运送给客户的送货方式。典型的送货选项包括

  • 免费送货
  • 快递送货
  • 国际送货
  • 优质国际送货

每种都有自己的成本。通常速度更快的方法/选项更昂贵。

使用 Payment Request API 的商家可以将此选择委托给支付应用。支付应用可以使用该信息构建 UI 并让客户选择送货选项。

Shipping option picker UI
送货选项选择器 UI

商家 Payment Request API 中指定的送货选项列表会作为 PaymentRequestEvent 的属性传播到支付应用的 Service Worker。

[商家]

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,支付应用可以从 Service Worker 向商家发送“送货选项变更”事件。Service Worker 应使用新的送货选项 ID 调用 PaymentRequestEvent.changeShippingOption()

Inform the merchant of a shipping option change
通知商家送货选项变更

[支付处理程序] 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 进行响应。

[商家]

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;

使用该对象更新前端的 UI。请参阅反映更新后的支付详细信息

反映更新后的支付详细信息

一旦商家完成更新支付详细信息,从 .changePaymentMethod().changeShippingAddress().changeShippingOption() 返回的 Promise 将会使用通用的 PaymentRequestDetailsUpdate 对象解析。支付处理程序可以使用结果来反映 UI 上更新后的总价和送货选项。

商家可能会因以下几个原因返回错误

  • 支付方式不可接受。
  • 送货地址在其支持区域之外。
  • 送货地址包含无效信息。
  • 送货选项对于提供的送货地址不可选择,或因其他一些原因。

使用以下属性来反映错误状态

  • error:人类可读的错误字符串。这是向客户展示的最佳字符串。
  • shippingAddressErrorsAddressErrors 对象,其中包含每个地址属性的详细错误字符串。如果您想打开一个表单,让客户编辑他们的地址,并且您需要直接将他们指向无效字段,这将非常有用。
  • paymentMethodErrors:特定于支付方式的错误对象。您可以要求商家提供结构化错误,但 Web Payments 规范作者建议将其保持为简单的字符串。

示例代码

您在此文档中看到的大多数示例代码都摘自以下工作示例应用

https://paymenthandler-demo.glitch.me

[支付处理程序] Service Worker

[支付处理程序] 前端

试用

  1. 转到 https://paymentrequest-demo.glitch.me/
  2. 转到页面底部。
  3. 按下 添加支付按钮
  4. 支付方式标识符字段中输入 https://paymenthandler-demo.glitch.me
  5. 按下字段旁边的支付按钮。