JavaScript内核与高级编程之:`JavaScript` 的 `Payment Request` API:其在 `Web` 支付流程中的应用。

各位老铁,晚上好!我是你们的老朋友,今天咱们来聊聊 JavaScript 里一个有点意思,但可能平时接触不多的东西:Payment Request API。这玩意儿,说白了,就是让你的网站支付流程更顺滑,用户体验更上一层楼的秘密武器。

一、啥是 Payment Request API?为啥要用它?

Payment Request API (支付请求 API),简称 PRA,它允许网站以一种标准、安全的方式向用户请求支付信息。想象一下,过去用户在你的网站上买东西,要填一大堆表格,姓名、地址、信用卡号,一不小心还填错了,那体验简直糟糕透了。PRA 的出现就是为了解决这个问题,它把这些信息交给浏览器或者支付应用(比如 Apple Pay、Google Pay),用户只需要点一下,就能完成支付。

为啥要用 PRA?

  1. 用户体验提升: 减少填写表单的痛苦,一键支付,用户更爽。
  2. 安全性更高: 网站不用直接接触用户的敏感支付信息,降低了被黑客攻击的风险。
  3. 更快的支付流程: 缩短支付时间,提高转化率,老板更高兴。
  4. 标准化: 统一的 API,方便开发者接入各种支付方式。

二、Payment Request API 的基本流程

PRA 的流程大概是这样的:

  1. 创建 PaymentRequest 对象: 告诉浏览器你要卖什么,价格多少,支持哪些支付方式。
  2. 显示支付界面: 浏览器弹出支付对话框,用户选择支付方式并授权。
  3. 处理支付结果: 验证支付信息,完成交易。
  4. 告诉用户结果: 交易成功还是失败,给用户一个明确的反馈。

三、代码实战:一步步接入 Payment Request API

咱们来撸一段代码,一步步演示如何接入 PRA。

1. 创建 PaymentRequest 对象

// 商品信息
const details = {
  total: {
    label: '总计',
    amount: { currency: 'CNY', value: '10.00' }
  }
};

// 支持的支付方式
const supportedInstruments = [
  {
    supportedMethods: 'basic-card',
    data: {
      supportedNetworks: ['visa', 'mastercard', 'amex'], // 支持的银行卡
      supportedTypes: ['credit', 'debit'] // 支持的卡类型
    }
  },
  {
    supportedMethods: 'https://android.com/pay',
    data: {
        "allowedCardNetworks": ["VISA", "MASTERCARD"]
    }
  },
  {
      supportedMethods: 'apple-pay',
      data: {
          version: 3,
          countryCode: 'CN',
          supportedNetworks: ['visa', 'mastercard', 'amex'],
          merchantCapabilities: ['supports3DS', 'supportsDebit', 'supportsCredit']
      }
  }
];

// 支付选项
const options = {
  requestShipping: false, // 是否需要收货地址
  requestPayerEmail: true, // 是否需要用户邮箱
  requestPayerPhone: false // 是否需要用户电话
};

try {
  const request = new PaymentRequest(supportedInstruments, details, options);

  // 检查是否支持 PRA
  request.canMakePayment().then(result => {
    if (result) {
      console.log('支持 Payment Request API');
    } else {
      console.log('不支持 Payment Request API');
    }
  }).catch(error => {
    console.error('检查支付支持失败:', error);
  });
    //监听支付方式更改事件
    request.addEventListener('paymentmethodchange', (evt) => {
        console.log('支付方式更改:', evt.methodDetails);
        //这里可以根据选择的支付方式更新商品价格
        evt.updateWith({
            total: {
                label: '总计',
                amount: { currency: 'CNY', value: '10.00' }
            }
        });
    });

  // 显示支付界面
  request.show()
    .then(paymentResponse => {
      // 处理支付结果
      console.log('支付信息:', paymentResponse);

      // 模拟后端验证支付信息
      setTimeout(() => {
        const paymentStatus = 'success'; // 假设支付成功

        if (paymentStatus === 'success') {
          paymentResponse.complete('success'); // 告诉浏览器支付成功
          alert('支付成功!');
        } else {
          paymentResponse.complete('fail'); // 告诉浏览器支付失败
          alert('支付失败!');
        }
      }, 2000); // 模拟 2 秒的后端处理时间
    })
    .catch(error => {
      console.error('支付失败:', error);
      alert('支付失败:' + error);
    });

} catch (error) {
  console.error('创建 PaymentRequest 对象失败:', error);
  alert('创建支付请求失败:' + error);
}

代码解释:

  • details: 定义了商品的总价。currency 是货币单位,value 是价格。
  • supportedInstruments: 定义了支持的支付方式。这里我们支持 basic-card(信用卡/借记卡),https://android.com/pay (Google Pay) 和 apple-pay
    • basic-card: supportedNetworks 指定了支持的银行卡类型,supportedTypes 指定了支持的卡类型(信用卡/借记卡)。
    • https://android.com/pay: 需要配置 allowedCardNetworks,指定支持的银行卡网络。
    • apple-pay: 需要配置 versioncountryCodesupportedNetworks, merchantCapabilities
  • options: 定义了是否需要收货地址、邮箱、电话等信息。
  • request.show(): 显示支付界面,用户选择支付方式并授权。
  • paymentResponse: 包含了用户的支付信息,你需要把这些信息发送到后端进行验证。
  • paymentResponse.complete(): 告诉浏览器支付结果,'success' 表示成功,'fail' 表示失败。
  • paymentmethodchange: 事件监听,当用户更改支付方式时触发,可以根据选择的支付方式动态更新订单信息。

2. HTML 结构

<!DOCTYPE html>
<html>
<head>
  <title>Payment Request API 示例</title>
</head>
<body>
  <h1>Payment Request API 示例</h1>
  <button id="paymentButton">立即支付</button>

  <script>
    // 上面的 JavaScript 代码放在这里
    document.getElementById('paymentButton').addEventListener('click', function() {
        // 将上面的Payment Request API 代码放在这里
        // 商品信息
        const details = {
          total: {
            label: '总计',
            amount: { currency: 'CNY', value: '10.00' }
          }
        };

        // 支持的支付方式
        const supportedInstruments = [
          {
            supportedMethods: 'basic-card',
            data: {
              supportedNetworks: ['visa', 'mastercard', 'amex'], // 支持的银行卡
              supportedTypes: ['credit', 'debit'] // 支持的卡类型
            }
          },
          {
            supportedMethods: 'https://android.com/pay',
            data: {
                "allowedCardNetworks": ["VISA", "MASTERCARD"]
            }
          },
          {
              supportedMethods: 'apple-pay',
              data: {
                  version: 3,
                  countryCode: 'CN',
                  supportedNetworks: ['visa', 'mastercard', 'amex'],
                  merchantCapabilities: ['supports3DS', 'supportsDebit', 'supportsCredit']
              }
          }
        ];

        // 支付选项
        const options = {
          requestShipping: false, // 是否需要收货地址
          requestPayerEmail: true, // 是否需要用户邮箱
          requestPayerPhone: false // 是否需要用户电话
        };

        try {
          const request = new PaymentRequest(supportedInstruments, details, options);

          // 检查是否支持 PRA
          request.canMakePayment().then(result => {
            if (result) {
              console.log('支持 Payment Request API');
            } else {
              console.log('不支持 Payment Request API');
            }
          }).catch(error => {
            console.error('检查支付支持失败:', error);
          });
            //监听支付方式更改事件
            request.addEventListener('paymentmethodchange', (evt) => {
                console.log('支付方式更改:', evt.methodDetails);
                //这里可以根据选择的支付方式更新商品价格
                evt.updateWith({
                    total: {
                        label: '总计',
                        amount: { currency: 'CNY', value: '10.00' }
                    }
                });
            });

          // 显示支付界面
          request.show()
            .then(paymentResponse => {
              // 处理支付结果
              console.log('支付信息:', paymentResponse);

              // 模拟后端验证支付信息
              setTimeout(() => {
                const paymentStatus = 'success'; // 假设支付成功

                if (paymentStatus === 'success') {
                  paymentResponse.complete('success'); // 告诉浏览器支付成功
                  alert('支付成功!');
                } else {
                  paymentResponse.complete('fail'); // 告诉浏览器支付失败
                  alert('支付失败!');
                }
              }, 2000); // 模拟 2 秒的后端处理时间
            })
            .catch(error => {
              console.error('支付失败:', error);
              alert('支付失败:' + error);
            });

        } catch (error) {
          console.error('创建 PaymentRequest 对象失败:', error);
          alert('创建支付请求失败:' + error);
        }
    });
  </script>
</body>
</html>

3. 注意事项

  • HTTPS: 必须在 HTTPS 环境下使用,因为 PRA 涉及到用户的敏感支付信息。
  • 用户授权: 用户必须授权才能使用 PRA,浏览器会弹出授权对话框。
  • 后端验证: 支付信息必须在后端进行验证,防止恶意攻击。
  • 错误处理: 要处理各种可能出现的错误,比如用户取消支付、支付方式不支持等等。

四、Payment Request API 的高级用法

除了基本用法,PRA 还有一些高级用法,可以让你更好地控制支付流程。

1. Shipping Options (收货地址选项)

如果你的商品需要邮寄,你可以使用 requestShipping 选项来请求用户的收货地址。

const options = {
  requestShipping: true, // 需要收货地址
  requestPayerEmail: true,
  requestPayerPhone: false
};

// 监听 shippingaddresschange 事件
request.addEventListener('shippingaddresschange', (evt) => {
  console.log('收货地址更改:', evt.shippingAddress);
  // 根据收货地址计算运费
  const shippingOptions = [
    {
      id: 'standard',
      label: '标准快递',
      amount: { currency: 'CNY', value: '5.00' },
      selected: true
    },
    {
      id: 'express',
      label: '加急快递',
      amount: { currency: 'CNY', value: '10.00' }
    }
  ];

  const details = {
    total: {
      label: '总计',
      amount: { currency: 'CNY', value: (10 + 5).toFixed(2) } // 商品价格 + 运费
    },
    displayItems: [
      {
        label: '商品',
        amount: { currency: 'CNY', value: '10.00' }
      },
      {
        label: '运费',
        amount: { currency: 'CNY', value: '5.00' }
      }
    ],
    shippingOptions: shippingOptions
  };

  evt.updateWith({
    status: 'success',
    shippingOptions: shippingOptions,
    details: details
  });
});

// 监听 shippingoptionchange 事件
request.addEventListener('shippingoptionchange', (evt) => {
  console.log('收货选项更改:', evt.shippingOption);
  // 根据收货选项更新总价
  let shippingCost = 0;
  if (evt.shippingOption === 'express') {
    shippingCost = 10;
  } else {
    shippingCost = 5;
  }

  const details = {
    total: {
      label: '总计',
      amount: { currency: 'CNY', value: (10 + shippingCost).toFixed(2) } // 商品价格 + 运费
    },
    displayItems: [
      {
        label: '商品',
        amount: { currency: 'CNY', value: '10.00' }
      },
      {
        label: '运费',
        amount: { currency: 'CNY', value: shippingCost.toFixed(2) }
      }
    ]
  };

  evt.updateWith({
    status: 'success',
    details: details
  });
});

代码解释:

  • requestShipping: true: 开启收货地址请求。
  • shippingaddresschange 事件:当用户修改收货地址时触发,你可以在这里根据收货地址计算运费。
  • shippingoptionchange 事件:当用户修改收货选项(比如选择标准快递还是加急快递)时触发,你可以在这里根据收货选项更新总价。
  • evt.updateWith(): 更新支付界面的信息,比如总价、运费等。

2. Payment Method Change (支付方式更改)

当用户选择不同的支付方式时,你可能需要更新订单信息,比如手续费、折扣等等。

// 监听 paymentmethodchange 事件
request.addEventListener('paymentmethodchange', (evt) => {
  console.log('支付方式更改:', evt.methodDetails);
  // 根据支付方式更新订单信息
  let discount = 0;
  if (evt.methodName === 'basic-card' && evt.methodDetails.cardNetwork === 'visa') {
    discount = 2; // Visa 卡有 2 元折扣
  }

  const details = {
    total: {
      label: '总计',
      amount: { currency: 'CNY', value: (10 - discount).toFixed(2) } // 商品价格 - 折扣
    },
    displayItems: [
      {
        label: '商品',
        amount: { currency: 'CNY', value: '10.00' }
      },
      {
        label: '折扣',
        amount: { currency: 'CNY', value: (-discount).toFixed(2) }
      }
    ]
  };

  evt.updateWith({
    status: 'success',
    details: details
  });
});

代码解释:

  • paymentmethodchange 事件:当用户修改支付方式时触发,你可以在这里根据支付方式更新订单信息。
  • evt.methodName: 支付方式的名称,比如 'basic-card'
  • evt.methodDetails: 支付方式的详细信息,比如银行卡类型、卡号等等。
  • evt.updateWith(): 更新支付界面的信息,比如总价、折扣等。

五、Payment Request API 的兼容性

虽然 PRA 很好用,但并不是所有浏览器都支持它。

浏览器 支持情况
Chrome 支持
Firefox 支持
Safari 支持
Edge 支持
iOS Safari 支持
Android Chrome 支持

在不支持 PRA 的浏览器中,你需要提供其他的支付方式,比如传统的表单支付。

if (window.PaymentRequest) {
  // 支持 Payment Request API
  // 使用 PRA 进行支付
} else {
  // 不支持 Payment Request API
  // 使用传统的表单支付
  alert('您的浏览器不支持 Payment Request API,请使用其他支付方式。');
}

六、Payment Request API 的安全性

PRA 的安全性主要体现在以下几个方面:

  1. HTTPS: 必须在 HTTPS 环境下使用,保证数据传输的安全性。
  2. 用户授权: 用户必须授权才能使用 PRA,防止恶意网站盗用用户的支付信息。
  3. 后端验证: 支付信息必须在后端进行验证,防止恶意攻击。
  4. 令牌化: 支付信息通常会被令牌化,网站不会直接接触用户的敏感支付信息。

七、Payment Request API 的未来

PRA 的未来一片光明,随着越来越多的浏览器和支付方式的支持,它将成为 Web 支付的主流方式。

  • 更多的支付方式: 将支持更多的支付方式,比如银行转账、数字货币等等。
  • 更强大的功能: 将提供更强大的功能,比如分期付款、订阅支付等等。
  • 更好的用户体验: 将提供更好的用户体验,比如更快的支付速度、更简单的支付流程等等。

八、总结

Payment Request API 是一个非常有用的 API,它可以让你的网站支付流程更顺滑,用户体验更上一层楼。虽然它有一些兼容性问题,但随着越来越多的浏览器和支付方式的支持,它将成为 Web 支付的主流方式。

今天就先聊到这里,希望大家有所收获!如果有什么问题,欢迎随时提问。

下课!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注