PAYATHON 2026

alipay-sdk-python中app pay支付成功但未收到回调通知

支付小周

结论

app pay 支付成功却收不到异步通知,通常不是支付结果有问题,而是生成 App 支付订单时未正确设置 notify_url,或支付宝服务器无法访问该回调地址。

客户端在 App 支付完成后返回的结果不能代替服务端异步通知。需要检查实际提交给 alipay.trade.app.pay 的请求参数,确认其中包含正确的 notify_url。回调接口还要能够接收 POST 请求、验证支付宝签名,并在处理成功后返回纯文本 success。

重点排查项

1. 确认 App 支付订单设置了 notify_url

page pay 和 app pay 使用不同的接口。即使网页支付已经配置回调地址,App 支付也不会自动复用。

使用 alipay-sdk-python 时,可以在初始化客户端时设置默认通知地址:

from alipay import AliPay

alipay = AliPay(
    appid="你的 AppID",
    app_notify_url="https://example.com/alipay/notify",
    app_private_key_string=app_private_key_string,
    alipay_public_key_string=alipay_public_key_string,
    sign_type="RSA2",
    debug=False,
)

然后生成 App 支付订单:

order_string = alipay.api_alipay_trade_app_pay(
    out_trade_no="IM2FAJUCT",
    total_amount="0.01",
    subject="订单标题",
)

如果当前 SDK 版本或封装方式允许在调用接口时单独传入 notify_url,也可以显式设置:

order_string = alipay.api_alipay_trade_app_pay(
    out_trade_no="IM2FAJUCT",
    total_amount="0.01",
    subject="订单标题",
    notify_url="https://example.com/alipay/notify",
)

不同 Python 支付宝 SDK 的方法签名可能不同。如果调用时报 unexpected keyword argument 'notify_url',应通过初始化参数 app_notify_url 进行配置。无论采用哪种方式,都要检查最终生成并提交的 App 支付请求,确认其中确实包含 notify_url。

return_url 用于浏览器同步跳转,不能代替 notify_url。

2. 确认回调地址可从公网访问

异步通知由支付宝服务器发起,因此回调地址需要满足以下条件:

  • 可以通过公网域名访问;
  • 建议使用有效的 HTTPS 证书;
  • 不依赖登录状态、Cookie 或前端 Token;
  • 不受内网、防火墙、安全组或错误的 IP 白名单配置影响;
  • 路由允许 POST 请求;
  • 不会被 CSRF 校验直接拦截;
  • 不会发生异常的 HTTP 到 HTTPS 跳转;
  • 接口能在合理时间内处理请求并返回 HTTP 200。

不要使用以下地址:

http://127.0.0.1:8000/alipay/notify
http://localhost/alipay/notify
http://192.168.x.x/alipay/notify

可以先从外网环境向回调地址发送一次普通 POST 请求,再查看应用日志、网关日志和 Web 服务器访问日志,确认请求能够到达。

3. 正确接收表单格式的回调数据

支付宝异步通知通常采用 application/x-www-form-urlencoded 格式,而不是 JSON。以 Flask 为例:

from flask import Flask, request, Response

app = Flask(__name__)

@app.post("/alipay/notify")
def alipay_notify():
    callback_data = request.form.to_dict()

    signature = callback_data.pop("sign", None)
    callback_data.pop("sign_type", None)

    if not signature:
        return Response("failure", status=400, mimetype="text/plain")

    if not alipay.verify(callback_data, signature):
        return Response("failure", status=400, mimetype="text/plain")

    # 验签成功后还需要核对订单信息
    out_trade_no = callback_data.get("out_trade_no")
    trade_status = callback_data.get("trade_status")
    total_amount = callback_data.get("total_amount")
    callback_app_id = callback_data.get("app_id")

    if callback_app_id != "你的 AppID":
        return Response("failure", status=400, mimetype="text/plain")

    order = load_order(out_trade_no)
    if order is None:
        return Response("failure", status=400, mimetype="text/plain")

    if total_amount != order.total_amount:
        return Response("failure", status=400, mimetype="text/plain")

    if trade_status in ("TRADE_SUCCESS", "TRADE_FINISHED"):
        mark_order_paid_once(
            order=order,
            alipay_trade_no=callback_data.get("trade_no"),
        )

    return Response("success", mimetype="text/plain")

其中,load_order 和 mark_order_paid_once 需要由业务系统实现,分别用于查询订单和更新订单状态。

验签必须使用支付宝公钥,不能使用应用公钥或应用私钥。生产环境与沙箱环境的密钥、网关和 AppID 也不能混用。

4. 回调成功后必须返回纯文本 success

业务处理成功后,接口应直接返回:

success

不要返回 JSON:

{"status": "success"}

也不要返回 HTML 页面、重定向响应或带有额外字符的内容。如果支付宝没有收到符合要求的响应,可能会继续重试通知,但业务系统不能只依靠重试机制保证订单状态一致。

5. 检查网关和应用日志

可以按照请求链路逐层排查:

  1. 检查生成订单时记录的 notify_url。
  2. 检查 Nginx、负载均衡或 API 网关访问日志。
  3. 检查应用路由是否收到 POST 请求。
  4. 检查请求是否被 WAF、CSRF、中间件或鉴权逻辑拦截。
  5. 检查验签失败日志。
  6. 检查业务处理是否抛出异常或触发数据库回滚。
  7. 检查最终响应正文是否严格为 success。

如果网关日志中完全没有支付宝请求,应优先确认 notify_url 是否提交成功,以及回调地址能否从公网访问。如果网关收到了请求,但应用没有收到,需要检查代理转发和路由配置。如果应用已经收到请求,订单状态却没有更新,则应检查验签、金额核对和业务事务处理。

对已支付订单进行主动查询

配置错误或网络问题可能导致业务系统没有处理异步通知,因此不能只依赖客户端提交的“支付成功”结果。可以使用 out_trade_no 主动查询交易状态:

result = alipay.api_alipay_trade_query(
    out_trade_no="IM2FAJUCT"
)

if result.get("code") == "10000":
    trade_status = result.get("trade_status")

    if trade_status in ("TRADE_SUCCESS", "TRADE_FINISHED"):
        # 核对 app_id、订单金额、商户身份等信息后,
        # 再以幂等方式更新本地订单
        pass

查询结果只能用于服务端补偿。更新订单前,仍要核对商户订单号、交易金额、AppID 和收款方身份等信息。

还可以增加定时补偿任务,对长时间处于“待支付”状态的订单调用交易查询接口,避免一次异步通知异常造成订单长期不一致。

注意事项

  • App 客户端返回的支付结果可能被伪造,不能直接据此发货或开通服务。
  • 回调处理必须具备幂等性。同一笔订单即使收到多次通知,也只能执行一次业务变更。
  • 验签成功不代表订单一定可信,还要核对 app_id、out_trade_no、total_amount、seller_id 等字段。
  • 金额建议使用 Decimal 或规范化后的字符串进行比较,避免浮点数精度问题。
  • 回调接口应先完成必要校验和可靠落库,再返回 success。
  • 不要在回调处理中执行耗时较长的任务。订单落库后,可以交给消息队列异步处理。
  • 日志可以记录 out_trade_no、trade_no 和 trade_status,但不能记录应用私钥等敏感信息。
  • 如果重新生成订单参数,客户端必须使用新的完整订单字符串,不能继续使用此前未包含 notify_url 的缓存参数。

针对这个问题,应先检查 out_trade_no=IM2FAJUCT 对应的 App 支付请求是否实际携带了正确的 notify_url。如果没有,需要在 AliPay 初始化时设置 app_notify_url,重新生成订单字符串,再结合公网访问日志确认支付宝通知是否到达。

备注:内容仅供参考。