Payment Request API:浏览器托管的结账流程
一句话: Payment Request API 让浏览器托管结账流程——浏览器使用用户已注册的存储卡片、 数字钱包或其他支付方式呈现原生支付面板——使你无需构建自定义支付 UI 或在页面上处理原始 卡片数据,即可获得流畅的结账体验。
PaymentRequest 以支付方式标识符数组为第一个参数构造,描述可接受的支付方式。有两类:
- 标准化方式:基于 URL 的标识符,如
"basic-card"(已废弃,推荐使用处理器专用方式) 以及平台专用方式,如"https://apple.com/apple-pay"或"https://google.com/pay"。 - 处理器专用方式:目前最常用的方式。传入支付处理器自己的方式标识符(如 Stripe 的
"https://stripe.com/pay")。处理器的 Payment Handler 负责协商细节。
第二个构造参数描述用户要支付什么:
const details = { total: { label: '合计', amount: { currency: 'CNY', value: '199.00' } }, displayItems: [ { label: '专业版订阅', amount: { currency: 'CNY', value: '199.00' } }, ],};// 1. 构造——此时不显示任何 UIconst request = new PaymentRequest( [{ supportedMethods: 'https://google.com/pay', data: { /* 处理器配置 */ } }], details, { requestPayerName: true, requestPayerEmail: true });
// 2. 检查是否至少有一种方式可用(可选但推荐)const canMakePayment = await request.canMakePayment();
// 3. 显示浏览器原生支付面板(必须在用户手势内)try { const response = await request.show(); // PaymentResponse // 4. 在服务端处理,再完成 await processOnServer(response.toJSON()); await response.complete('success');} catch (err) { if (err.name === 'AbortError') { // 用户关闭了面板——不是错误 } else { throw err; }}安全上下文(HTTPS)
Section titled “安全上下文(HTTPS)”Payment Request API 仅在安全上下文中可用——HTTPS 或 localhost。在普通 HTTP 下,
PaymentRequest 构造函数为 undefined。
用户手势要求
Section titled “用户手势要求”request.show() 必须在用户激活(点击、轻触或类似瞬时事件)时调用。从定时器或非交互
异步链中调用,某些浏览器会抛出 SecurityError 或以 NotAllowedError 拒绝。
canMakePayment()
Section titled “canMakePayment()”canMakePayment() 在不显示任何 UI 的情况下检查用户设备上至少一种请求的支付方式是否可用。
用它决定是显示支付请求按钮还是回退到重定向结账:
const available = await request.canMakePayment();if (!available) { // 重定向到托管结账页}注意:部分浏览器会对 canMakePayment() 的调用频率进行节流以防滥用。
配送与联系人字段
Section titled “配送与联系人字段”在第三个构造参数 PaymentOptions 中传入可选标志,向用户请求额外信息:
requestShipping: true— 显示配送地址选择器;需要在details中至少提供一个shippingOption。requestPayerName、requestPayerEmail、requestPayerPhone— 从存储的配置文件中 请求联系人字段。
收到 PaymentResponse 后,始终调用 response.complete() 并传入 'success' 或
'fail',以告知浏览器处理已完成、面板可以关闭。不调用 complete() 会让面板停留在
挂起状态。
浏览器与生态支持
Section titled “浏览器与生态支持”| Browser / Platform | Support | Since | Confidence | Source | Notes |
|---|---|---|---|---|---|
| Chrome (Android) | ✅ yes | 61 | high | ref | — |
| Chrome (Desktop) | ✅ yes | 61 | high | ref | — |
| Edge (Desktop) | ✅ yes | 79 | high | ref | — |
| Safari (iOS) | ✅ yes | 11.1 | high | ref | Backed by Apple Pay as the payment method. |
| Safari (macOS) | ✅ yes | 11.1 | high | ref | Backed by Apple Pay. |
| Firefox (Desktop) | ❌ no | — | medium | ref | Implementation shipped then disabled; not available by default. |
| Samsung Internet | ✅ yes | 7.0 | medium | ref | — |
Ecosystem & commercial policy
| Entity | Type | Context | Status | Sponsored | Notes |
|---|---|---|---|---|---|
| Apple Pay | payment_sdk | Safari / iOS | ✅ supported | No | Works in Safari via Payment Request; merchant-domain verification required. |
| Stripe | payment_sdk | Cross-browser | ✅ supported | No | Stripe wraps Payment Request as the Payment Request Button / Payment Element. |
| Google Play billing | store_policy | Google Play TWA | ❌ unsupported | No | TWAs distributing digital goods must use Play Billing, not Payment Request, per Play policy. |
当前各浏览器数据请参见 /compatibility/。
决策判定框架
Section titled “决策判定框架”| 决策问题 | 建议行为 | 理由 |
|---|---|---|
| 想提供原生钱包结账? | 使用 PaymentRequest 并配合处理器的支付方式标识符。 |
避免构建自定义卡片输入 UI;使用已存储的凭据。 |
| 想在显示按钮前确认原生方式是否可用? | 调用 canMakePayment() 并以结果门控按钮。 |
防止显示打开空面板或不支持面板的按钮。 |
| 用户需要选择配送地址? | 设置 requestShipping: true 并填充 shippingOptions。 |
浏览器收集地址;shippingaddresschange 监听器更新总价。 |
| 面向不支持 Payment Request 的浏览器? | 提供标准重定向到托管结账页的回退。 | iOS Safari 和 Android Chrome 均支持,但桌面端覆盖不一。 |
- 仅在 HTTPS 下构造
PaymentRequest并调用show()。 - 在用户手势事件处理器内调用
show()。 - 服务端处理后调用
response.complete('success' | 'fail')。 - 静默捕获
show()的AbortError——用户关闭了面板。 - 用
canMakePayment()决定显示原生支付按钮还是回退 UI。 - 切勿记录或存储原始
PaymentResponse数据——立即传给后端处理。