PAYATHON 2026

支付宝 callback 延迟3个月返回支付成功通知的原因

支付小周

结论

仅凭“2021/07/10 支付”和“2021/10/11 收到成功通知”这两个时间点,无法认定支付宝延迟了三个月,也不能直接判断 MISUMI 系统发生了故障。

正常情况下,支付宝会在支付成功后较短时间内发送异步通知。即使通知需要重试,首次通知直到三个月后才到达,也不符合常见的重试特征。可能的原因包括:

  • 7 月已经收到通知,但在接收、验签、业务处理或日志记录环节失败;
  • 10 月触发了补单、对账或人工重放,系统误将处理时间当成支付宝回调时间;
  • 订单在 7 月只是创建或发起支付,实际支付成功时间并不是 7 月;
  • 同一商户订单号被重复使用,不同支付记录因此关联到了同一笔 MISUMI 订单;
  • 回调接口曾返回非成功响应,支付宝进行过重试,但实际重试周期需要通过支付宝侧日志确认;
  • 10 月收到的请求并非支付宝原始通知,而是内部系统重新投递的历史消息。

要确定责任点,需要同时核对支付宝交易状态、原始通知记录和 MISUMI 内部处理链路。

首先确认三个时间的含义

调查时不能只比较“下单时间”和“回调处理时间”,至少要区分以下三个时间:

  1. MISUMI 创建订单的时间;
  2. 支付宝交易实际支付成功的时间;
  3. MISUMI 接口收到并处理通知的时间。

支付宝通知中的 gmt_payment 通常表示交易付款时间,notify_time 表示通知生成时间。MISUMI 应用日志中的时间,则只是服务器记录请求或处理消息的时间。三者含义不同,不能混用。

对于 2021/10/11 收到的通知,可以根据字段作如下判断:

  • gmt_payment 为 2021/07/10,说明通知对应的是一笔历史付款;
  • notify_time 也为 2021/07/10,但 MISUMI 到 10 月才处理,应优先检查内部消息积压、日志补录或消息重放;
  • notify_time 为 2021/10/11,需要确认请求是否确实来自支付宝,以及当天为何重新生成了通知;
  • gmt_payment 为 2021/10/11,则“7 月已经完成支付”这一判断可能有误。

建议的调查步骤

1. 查询支付宝侧交易记录

使用支付宝交易号 120889WP0172E32B00 查询前,需要先确认该值究竟是支付宝交易号 trade_no,还是 MISUMI 传给支付宝的商户订单号 out_trade_no。从编号形式看,它也可能是商户侧订单号,不能仅凭名称判断。

需要重点核对以下字段:

out_trade_no
trade_no
trade_status
gmt_create
gmt_payment
notify_time
total_amount
seller_id
app_id

如果通过开放平台接口查询,应使用商户订单号或支付宝交易号查询实际交易,不能只看本地数据库中的状态。例如:

AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
request.setBizContent("""
{
  "out_trade_no": "120889WP0172E32B00"
}
""");

AlipayTradeQueryResponse response = alipayClient.execute(request);

if (response.isSuccess()) {
    System.out.println(response.getTradeNo());
    System.out.println(response.getTradeStatus());
    System.out.println(response.getTotalAmount());
} else {
    System.out.println(response.getCode());
    System.out.println(response.getSubCode());
    System.out.println(response.getSubMsg());
}

具体的 SDK 初始化方式、接口权限和可查询期限,应以当时接入的支付宝产品及 SDK 版本为准。

2. 调取 7 月和 10 月的原始访问日志

检查回调入口在以下时间段是否收到过请求:

2021/07/10 前后
2021/10/11 前后

需要查询的记录包括:

  • 网关、负载均衡或反向代理访问日志;
  • callback 应用日志;
  • 验签失败日志;
  • 数据库更新记录;
  • 消息队列的生产与消费记录;
  • 定时补单和对账任务日志;
  • 人工重放或运维操作记录。

应保存并比对请求中的 notify_id、trade_no、out_trade_no、notify_time、gmt_payment 和 trade_status,同时检查接口返回的 HTTP 状态码与响应正文。

如果 7 月的访问日志中已经存在相同的 trade_no 或 notify_id,就说明支付宝并不是三个月后才首次通知。问题更可能出在 MISUMI 的接收或处理环节。

3. 检查回调响应是否正确

支付宝异步通知接口完成验签和业务处理后,通常需要返回约定的成功字符串。如果返回内容不符合要求、连接超时或出现 HTTP 5xx,支付宝可能会将通知视为失败并进行重试。

示例:

@PostMapping("/alipay/notify")
public String receiveNotify(HttpServletRequest request) {
    Map<String, String> params = extractParameters(request);

    boolean valid = AlipaySignature.rsaCheckV1(
        params,
        alipayPublicKey,
        StandardCharsets.UTF_8.name(),
        "RSA2"
    );

    if (!valid) {
        return "failure";
    }

    String tradeStatus = params.get("trade_status");
    if ("TRADE_SUCCESS".equals(tradeStatus)
            || "TRADE_FINISHED".equals(tradeStatus)) {
        processPaymentIdempotently(params);
        return "success";
    }

    return "success";
}

实际使用的验签方法和参数必须与项目采用的支付宝 SDK 版本一致。不能为了停止重试,在验签失败、金额不一致或商户身份不匹配时返回 success。

4. 检查是否存在内部补单或消息重放

如果支付宝侧记录显示支付已在 7 月完成,但 MISUMI 到 10 月才更新订单状态,应重点检查:

  • 定时查询交易状态的补单程序;
  • 每日对账文件处理任务;
  • 消息队列死信重新消费;
  • 数据迁移或历史订单修复;
  • 10 月进行的上线、发布或故障恢复操作;
  • 客服或运维人员手工修改订单状态的记录。

很多系统会把“订单状态最后更新时间”显示成“回调时间”。如果 10 月的状态变更来自补单任务,这个时间并不表示支付宝当天发送了 callback。

5. 检查订单号是否重复

查询 WP0172E32B00 和 120889WP0172E32B00 是否各自只对应一笔支付请求,并核对:

  • 是否重复创建过支付宝交易;
  • 是否存在多个 trade_no;
  • 是否曾经取消后重新支付;
  • 测试环境和生产环境是否使用了相同订单号;
  • 交易是否由不同的 app_id 或 seller_id 发起。

订单号重复或关联关系错误,可能导致旧交易通知更新新订单,也可能让新交易通知被误认为延迟到达的历史订单通知。

回调处理应具备幂等性

异步通知可能重复到达,业务系统不能把“是否收到过 callback”作为唯一判断条件,而应使用支付宝交易号或商户订单号进行幂等更新。

BEGIN;

SELECT payment_status, amount
FROM payment_order
WHERE out_trade_no = '120889WP0172E32B00'
FOR UPDATE;

-- 校验 app_id、seller_id、订单金额及订单归属。
-- 如果已经是 PAID,则记录重复通知,不再次发货或扣减库存。
-- 如果尚未支付,则更新状态,并保存 trade_no、gmt_payment、notify_id。

COMMIT;

建议为 trade_no 和 out_trade_no 设置适当的唯一约束,并分别保存“原始通知接收时间”“验签结果”“业务处理时间”和“订单状态更新时间”,避免以后再次混淆。

提交工单时需要提供的信息

向支付宝提交工单时,建议提供以下信息:

  • 商户 app_id 和 seller_id;
  • trade_no 与 out_trade_no;
  • 2021/07/10 和 2021/10/11 的完整时间及时区;
  • 10 月通知中经过脱敏的原始参数;
  • notify_id、notify_time、gmt_payment 和 trade_status;
  • callback URL;
  • MISUMI 接口的访问日志、HTTP 状态码和响应正文;
  • 是否执行过补单、对账、消息重放或人工操作;
  • 订单金额及本地状态变化记录。

私钥、应用密钥、完整签名材料、Cookie 和访问令牌不得提交到公开工单或聊天记录中。

判断责任点的方法

最终可以根据以下证据判断责任点:

  • 如果支付宝证明 7 月已多次发送通知,而 MISUMI 未成功处理,应检查 MISUMI 的网关、应用、数据库或消息队列;
  • 如果支付宝侧直到 10 月才生成通知,应由支付宝进一步说明通知产生的原因;
  • 如果 10 月没有支付宝通知记录,但 MISUMI 的订单状态发生了变化,应检查内部补单、对账或人工处理记录;
  • 如果支付宝实际付款时间为 10 月,应修正“7 月完成支付”的业务判断;
  • 如果发现多个交易号或重复订单号,应修复订单与支付交易之间的映射逻辑。

在取得支付宝侧通知记录和 MISUMI 原始访问日志之前,不宜直接将问题归因于任何一方。

备注:内容仅供参考。