PAYATHON 2026

付款码支付时如何获取用户关闭密码弹窗的取消行为

支付小周

结论

alipay.trade.pay 没有专门标识“用户关闭密码弹窗”的字段,也没有可稳定用于判断这一动作的错误码。商户无法仅凭该接口确认用户是否点击了密码弹窗的关闭按钮。

付款码交易需要用户输入密码时,alipay.trade.pay 可能返回处理中状态。商户应根据接口结果查询交易的最终状态。如果超过规定时间仍未支付,再撤销交易。前端可以提示“支付未完成”或“支付已取消”,但不能断言“用户关闭了密码弹窗”。

原因

密码弹窗是支付宝客户端内部的支付交互。商户支付接口提供的是交易结果,不是用户在客户端内的具体点击记录。

接口可能返回以下结果:

  • 支付成功;
  • 交易处理中,需要继续查询;
  • 支付失败;
  • 交易已关闭;
  • 商户主动撤销成功。

即使交易最终没有成功,也无法据此认定用户关闭了密码弹窗。网络超时、余额不足、风控限制和其他支付异常都可能产生类似结果。

推荐处理流程

1. 检查 alipay.trade.pay 的同步响应

先检查响应中的 code、sub_code 和相关业务字段:

  • code = 10000:支付成功;
  • code = 10003:等待用户付款或交易处理中,不能立即按支付失败处理;
  • 明确的业务失败:根据 sub_code 和 sub_msg 记录原因,并向用户显示合适的提示;
  • 网络超时或响应结果未知:不能直接判定支付失败,需要查询交易状态。

不要通过匹配 sub_msg 文本判断用户是否关闭了弹窗。提示文案可能发生变化,不适合用作程序分支条件。

2. 查询处理中或结果未知的交易

使用同一个 out_trade_no 调用 alipay.trade.query,主要检查 trade_status:

  • TRADE_SUCCESS:支付成功;
  • TRADE_FINISHED:交易完成;
  • WAIT_BUYER_PAY:仍在等待付款;
  • TRADE_CLOSED:交易已经关闭,无法继续付款。

如果查询结果仍是 WAIT_BUYER_PAY,可以在有限时间内短间隔轮询。商户应根据自己的收银业务设置轮询次数和总时长,不能无限查询。

3. 超过等待时间后撤销交易

达到商户设置的支付等待时间后,调用 alipay.trade.cancel 撤销交易。撤销成功后,收银端可以显示:

支付未完成,订单已取消,请重新付款。

这里的“订单已取消”表示交易已经关闭或撤销,不代表系统识别到了用户关闭密码弹窗的动作。

如果撤销结果不明确,需要继续查询最终状态,避免出现商户端显示已取消、用户却实际支付成功的情况。

Java 处理示例

以下代码用于说明状态处理思路。具体类名和字段访问方式以项目所使用的支付宝 Java SDK 版本为准。

AlipayTradePayRequest request = new AlipayTradePayRequest();
request.setBizContent(payBizContent);

AlipayTradePayResponse response = alipayClient.execute(request);

String code = response.getCode();

if ("10000".equals(code)) {
    // 支付成功
    showMessage("支付成功");
    savePaidResult(response);

} else if ("10003".equals(code)) {
    // 等待用户付款或交易处理中
    TradeResult result = queryUntilFinalState(outTradeNo);

    switch (result.getTradeStatus()) {
        case "TRADE_SUCCESS":
        case "TRADE_FINISHED":
            showMessage("支付成功");
            break;

        case "TRADE_CLOSED":
            showMessage("支付未完成,交易已取消");
            break;

        case "WAIT_BUYER_PAY":
            CancelResult cancelResult = cancelTrade(outTradeNo);

            if (cancelResult.isSuccess()) {
                showMessage("支付未完成,订单已取消,请重新付款");
            } else {
                // 撤销结果不确定时再次查询,不能直接认定失败
                enqueueReconciliation(outTradeNo);
                showMessage("支付结果确认中,请勿重复付款");
            }
            break;

        default:
            enqueueReconciliation(outTradeNo);
            showMessage("支付结果确认中,请稍后查看");
            break;
    }

} else {
    // 明确的业务失败
    log.warn(
        "alipay.trade.pay failed, code={}, subCode={}, subMsg={}",
        response.getCode(),
        response.getSubCode(),
        response.getSubMsg()
    );

    showMessage(buildSafePaymentMessage(response.getSubCode()));
}

查询时可以设置有限的轮询次数:

private TradeResult queryUntilFinalState(String outTradeNo)
        throws InterruptedException {

    int maxAttempts = 5;
    long intervalMillis = 2000L;

    for (int i = 0; i < maxAttempts; i++) {
        TradeResult result = queryTrade(outTradeNo);
        String status = result.getTradeStatus();

        if ("TRADE_SUCCESS".equals(status)
                || "TRADE_FINISHED".equals(status)
                || "TRADE_CLOSED".equals(status)) {
            return result;
        }

        Thread.sleep(intervalMillis);
    }

    return TradeResult.waitBuyerPay();
}

生产环境中不建议长期占用 Web 请求线程进行轮询。查询和补偿可以交给支付任务、消息队列或定时任务处理。

商户端提示建议

由于商户无法可靠识别用户关闭密码弹窗的动作,建议按照交易状态显示提示:

交易情况推荐提示
支付成功支付成功
等待付款请在支付宝中完成支付
已关闭或撤销成功支付未完成,订单已取消
明确失败支付失败,请更换支付方式或重试
状态未知支付结果确认中,请勿重复付款

如果商户自己的收银页面有“取消支付”按钮,可以记录该按钮的点击事件。但这个事件只能说明用户在商户端主动取消,不能说明用户关闭了支付宝密码弹窗。

注意事项

  • 不要把 10003 视为支付失败,此时交易仍有可能成功。
  • 不要根据接口耗时或客户端弹窗消失来推断支付结果。
  • 不要依赖 sub_msg 文本进行业务判断,应优先使用 code、sub_code 和 trade_status。
  • 查询、撤销和支付成功通知可能并发发生,需要使用同一个 out_trade_no 做幂等处理。
  • 撤销失败或响应超时后,必须继续查询并进行对账。
  • 如果业务必须统计“关闭密码弹窗”这一交互,只能通过能够观察该动作的客户端能力来获取。在没有对应官方字段或回调的情况下,alipay.trade.pay 无法单独完成这项统计。

备注:内容仅供参考。