PAYATHON 2026

Basic Web Payments Request API 示例无法弹出支付窗口

支付阿杰

结论

paymentRequest.show() 没有弹出信用卡选择窗口,通常与收款账户无关,更可能是以下原因:

  • 主流浏览器已逐步弃用或移除 "basic-card",当前浏览器中可能没有可用的支付处理程序。
  • show() 没有由用户点击等有效的用户激活操作直接触发。
  • 页面不在安全上下文中,例如通过普通 HTTP 访问。
  • show() 返回的 Promise 被拒绝,但代码没有捕获异常,所以看起来像是“什么也没发生”。

Payment Request API 不负责完成扣款。它用于调用浏览器的支付界面并收集支付信息,实际的授权、扣款和入账仍要通过支付服务商或支付网关处理。

先把实际错误显示出来

paymentRequest.show() 返回 Promise。原代码没有处理失败情况,至少应该加入 try...catch:

<button id="pay-button" type="button">Pay here</button>

<script>
document.getElementById("pay-button").addEventListener("click", async () => {
    if (!window.PaymentRequest) {
        console.error("This browser does not support the Payment Request API.");
        return;
    }

    const supportedPaymentMethods = [
        {
            supportedMethods: "basic-card"
        }
    ];

    const paymentDetails = {
        total: {
            label: "Total Cost",
            amount: {
                currency: "GBP",
                value: "1.00"
            }
        }
    };

    try {
        const paymentRequest = new PaymentRequest(
            supportedPaymentMethods,
            paymentDetails
        );

        const paymentResponse = await paymentRequest.show();

        console.log("Payment response:", paymentResponse);

        // 实际应用中,应先把支付数据提交到服务器处理。
        await paymentResponse.complete("success");
    } catch (error) {
        console.error("Payment request failed:", error.name, error.message);
    }
});
</script>

这段代码不能保证当前浏览器支持 "basic-card",但能把具体的失败原因显示出来。开发者工具控制台中常见的错误有 NotSupportedError、AbortError,以及与用户激活或安全上下文有关的错误。

为什么 "basic-card" 可能无法使用

PaymentRequest 是一个调用支付界面的通用 API,并不表示浏览器一定内置信用卡支付能力。浏览器要显示支付界面,通常需要同时满足两个条件:

  1. 浏览器支持 Payment Request API。
  2. 浏览器或操作系统中存在与 supportedMethods 匹配的支付处理程序。

检测到 window.PaymentRequest,只能说明 API 入口存在,不能证明 "basic-card" 可用。特别是 "basic-card",已经不适合作为现代浏览器新项目的支付方案。它能否使用,取决于浏览器、版本、操作系统和用户配置。

可以调用 canMakePayment() 检查支付能力:

const paymentRequest = new PaymentRequest(
    supportedPaymentMethods,
    paymentDetails
);

try {
    const canPay = await paymentRequest.canMakePayment();

    if (!canPay) {
        console.warn("No compatible payment handler is available.");
        return;
    }

    const paymentResponse = await paymentRequest.show();
    console.log(paymentResponse);
} catch (error) {
    console.error(error);
}

不过,canMakePayment() 只能作为参考,不能代替对 show() 的异常处理。它的返回结果也可能受浏览器隐私策略影响。

show() 必须由用户操作触发

支付窗口通常需要在按钮点击等有效的用户激活事件中直接打开。不要在页面加载时自动调用,也不要等点击后执行完较长的异步流程再调用:

payButton.addEventListener("click", async () => {
    try {
        const response = await paymentRequest.show();
        // ...
    } catch (error) {
        console.error(error);
    }
});

下面的写法可能因为用户激活状态已经失效而失败:

payButton.addEventListener("click", async () => {
    await someLongAsyncOperation();
    await paymentRequest.show();
});

如果必须先获取价格等数据,最好提前准备好,再让用户点击支付按钮。

页面必须处于安全上下文

Payment Request API 通常要求页面处于安全上下文:

  • 正式环境应使用 HTTPS。
  • 本地开发通常可以使用 http://localhost。
  • 直接打开 file:// 文件或通过普通 HTTP 域名访问时,API 可能无法正常调用。

可以这样检查:

console.log("Secure context:", window.isSecureContext);

如果结果为 false,应先处理 HTTPS 或本地开发服务器问题。

参数还需要注意两处细节

金额的 value 应该是符合支付金额格式的字符串:

value: "1.00"

不建议使用数字:

value: 1

变量名也必须保持一致。如果声明的是:

const supportedPaymentMethods = [];

构造时就要传入同一个变量:

new PaymentRequest(
    supportedPaymentMethods,
    paymentDetails,
    options
);

如果误写为未定义的 supportedMethods,代码会直接产生 ReferenceError,不会执行到 show()。

下一步应该如何配置

生产环境不应只依赖 "basic-card"。通常需要先选择支付服务商,再按照服务商文档配置对应的支付方法。例如,某些支付方式会使用 URL 作为标识:

const supportedPaymentMethods = [
    {
        supportedMethods: "https://payment-provider.example/pay",
        data: {
            merchantId: "YOUR_MERCHANT_ID"
        }
    }
];

这里的地址和字段只是结构示意,不能直接用于支付。实际配置必须由所选支付服务商提供,通常包括:

  • 商户账户和商户标识;
  • 允许使用的支付方式;
  • 域名验证或商户认证;
  • 前端支付方法配置;
  • 服务端支付授权与扣款接口;
  • 支付成功、失败和取消的处理;
  • 在服务端重新校验订单金额。

典型的支付流程如下:

  1. 用户点击支付按钮。
  2. 浏览器显示可用的支付方式。
  3. show() 返回 PaymentResponse。
  4. 前端把必要的支付数据发送到自己的服务器。
  5. 服务器调用支付服务商接口完成授权或扣款。
  6. 根据服务端返回的结果调用 response.complete("success") 或 response.complete("fail")。

因此,即使没有商户账户时能够显示支付窗口,也只能测试界面和数据收集流程,无法完成真实收款。PaymentResponse 不能直接证明支付成功,最终结果必须以服务器和支付服务商返回的信息为准。

备注:内容仅供参考。