alipay.trade.precreate 支付成功回调如何接收?
结论
alipay.trade.precreate 支持支付结果异步通知。创建预支付订单时,需要通过公共请求参数 notify_url 指定回调地址。用户扫码完成支付后,支付宝会向该地址发送 HTTP POST 表单请求。
服务端收到通知后,需要依次完成以下处理:
- 使用支付宝公钥验签;
- 校验
app_id、seller_id、out_trade_no和total_amount; - 根据
trade_status判断交易状态; - 幂等更新订单;
- 返回纯文本
success。
如果创建预支付订单时没有传入有效的 notify_url,或者支付宝无法通过公网访问该地址,服务端就收不到预期的支付通知。
创建订单时设置 notify_url
notify_url 是支付宝接口的公共请求参数,不能放在 biz_content 中。使用 Java SDK 时,可以直接调用 setNotifyUrl:
AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
request.setNotifyUrl("https://pay.example.com/alipay/notify");
request.setBizContent("""
{
"out_trade_no": "ORDER_202609090001",
"total_amount": "0.01",
"subject": "测试订单"
}
""");
AlipayTradePrecreateResponse response = alipayClient.execute(request);
if (response.isSuccess()) {
String qrCode = response.getQrCode();
// 将 qrCode 生成二维码供用户扫码
} else {
// 记录 sub_code、sub_msg 等错误信息
}
如果自行拼装请求,应把 notify_url 放在公共参数区域。例如:
method=alipay.trade.precreate
app_id=你的应用ID
charset=utf-8
sign_type=RSA2
timestamp=2026-09-09 12:00:00
version=1.0
notify_url=https://pay.example.com/alipay/notify
biz_content={...}
sign=...
notify_url 也参与请求签名,因此不能在签名完成后再添加或修改。
接收异步通知
支付宝发送的是 application/x-www-form-urlencoded 格式的 HTTP POST 请求,不是 JSON。下面是使用 Spring Boot 接收通知的示例:
@PostMapping(
value = "/alipay/notify",
produces = "text/plain;charset=UTF-8"
)
public String receiveAlipayNotify(HttpServletRequest request) {
Map<String, String> params = new HashMap<>();
request.getParameterMap().forEach((key, values) -> {
if (values != null && values.length > 0) {
params.put(key, String.join(",", values));
}
});
try {
boolean valid = AlipaySignature.rsaCheckV1(
params,
ALIPAY_PUBLIC_KEY,
"UTF-8",
"RSA2"
);
if (!valid) {
return "failure";
}
String appId = params.get("app_id");
String sellerId = params.get("seller_id");
String outTradeNo = params.get("out_trade_no");
String tradeNo = params.get("trade_no");
String tradeStatus = params.get("trade_status");
String totalAmount = params.get("total_amount");
// 以下信息必须与本地订单进行比对
if (!EXPECTED_APP_ID.equals(appId)) {
return "failure";
}
if (!EXPECTED_SELLER_ID.equals(sellerId)) {
return "failure";
}
Order order = orderService.findByOutTradeNo(outTradeNo);
if (order == null) {
return "failure";
}
if (new BigDecimal(totalAmount).compareTo(order.getTotalAmount()) != 0) {
return "failure";
}
if ("TRADE_SUCCESS".equals(tradeStatus)
|| "TRADE_FINISHED".equals(tradeStatus)) {
// 必须幂等处理:重复通知不能重复记账或重复发货
orderService.markPaidIfUnpaid(
outTradeNo,
tradeNo,
tradeStatus
);
}
return "success";
} catch (AlipayApiException e) {
// 记录异常,但不要打印私钥等敏感信息
return "failure";
}
}
不同版本的 SDK 在具体类名和方法签名上可能略有差异,但处理方式相同:先取得所有表单参数,再使用支付宝公钥和通知中的签名参数完成验签。
如何理解”触发通知”
“触发通知”是指交易状态发生符合接口规则的变化后,支付宝将交易结果推送到本次请求指定的 notify_url。
支付成功时,主要处理以下状态:
trade_status=TRADE_SUCCESS
部分交易在后续状态变化时,还可能收到以下通知:
trade_status=TRADE_FINISHED
业务系统不能把收到一次 HTTP 请求直接视为可以发货。只有验签和订单信息校验全部通过后,才能根据 trade_status 更新订单。
异步通知可能重复发送,所以订单处理必须具备幂等性。例如,订单只能从”待支付”更新为”已支付”一次。对于后续收到的重复通知,直接返回 success。
始终收不到通知时的排查顺序
1. 确认请求中确实传入了 notify_url
应检查最终发送给支付宝的请求参数,不能只看配置文件。常见问题包括:
- 只配置了应用网关,没有为当前请求设置
notify_url; - 把
notify_url错放在biz_content中; - 封装 SDK 时漏掉了
request.setNotifyUrl(...); - 完成签名后才追加
notify_url。
应用网关、授权回调地址和支付异步通知地址是三个不同的概念,不能相互替代。
2. 确认地址可从公网访问
回调地址不能使用:
http://localhost/...
http://127.0.0.1/...
http://192.168.x.x/...
应使用稳定的公网域名,例如:
https://pay.example.com/alipay/notify
还需要检查以下项目:
- DNS 是否可以正常解析;
- HTTPS 证书是否有效;
- 防火墙、安全组和反向代理是否允许访问;
- 路由是否接受
POST请求; - 是否受到强制登录、验证码或鉴权拦截;
- 是否存在 301、302 跳转;
- WAF 是否拦截了支付宝请求;
- 接口能否在较短时间内返回结果。
3. 不要按 JSON 解析
以下写法不适用于支付宝异步通知:
@RequestBody AlipayNotifyBody body
支付宝异步通知通常使用表单参数。服务端应通过 request.getParameterMap() 获取参数,或者直接接收对应的表单字段。
4. 检查服务端响应
处理成功后,响应体应为:
success
不要返回 JSON:
{"code":200,"message":"success"}
也不要返回 HTML 页面、额外空格或经过业务对象包装的内容。如果支付宝没有识别到成功响应,可能会继续重试通知。
5. 检查验签配置
验签必须使用支付宝公钥,不能使用应用公钥或应用私钥。同时确认:
sign_type与实际请求一致,通常是RSA2;- 字符集与请求配置一致,常见值为
UTF-8; - 验签参数包含支付宝通知中的全部有效参数;
- 不要再次对参数值进行 URL 编码或解码;
- 不要修改金额、时间等参数后再验签。
重要注意事项
异步通知是确认支付结果的主要渠道,但网络通知可能重复发送,也不一定会在固定时间内到达。生产环境通常还需要保留订单查询作为补偿机制,例如对长时间停留在”待支付”状态的订单进行低频查询或对账。这类查询用于容错补偿,无需让用户端持续轮询。
回调处理还应遵循以下原则:
- 先验签,再处理业务;
- 使用
BigDecimal比较金额,不要使用double; - 校验通知中的商户、应用和订单归属;
- 使用商户订单号
out_trade_no进行幂等控制; - 保存支付宝交易号
trade_no,用于后续退款和对账; - 完成可靠的本地状态更新后,再返回
success; - 可以把耗时操作交给消息队列,但需要保证订单落库与消息投递的一致性;
- 不能只根据
trade_status字段判断付款有效。
调用 alipay.trade.precreate 时,需要为当前请求设置一个支付宝能够从公网访问的 notify_url。回调接口收到通知后,应按”接收表单、验签、校验订单、幂等处理、返回 success”的顺序处理。
备注:内容仅供参考。
