PAYATHON 2026

支付宝 App 支付提示“商家订单参数异常”如何排查?

支付小周

结论

这段支付参数最明显的问题是 notify_url 重复拼接了域名。

解码后的实际内容是:

https://www.starseed07.com/https://www.starseed07.com/api/payments/alipay/notify-url/

正确地址应为:

https://www.starseed07.com/api/payments/alipay/notify-url/

先修正服务端生成 notify_url 的逻辑,再重新生成订单参数和签名。不要直接修改已经签名的字符串,否则签名会失效。

如何检查这类订单字符串

支付宝 App 支付的订单字符串本质上是一组经过 URL 编码的查询参数。可以先进行 URL 解码,再逐项检查。

使用 Python 查看参数:

from urllib.parse import parse_qs, unquote_plus

order_string = "app_id=2021000119627334&biz_content=..."

params = parse_qs(order_string, keep_blank_values=True)

for key, values in params.items():
    print(f"{key}: {values[0]}")

print("biz_content:", unquote_plus(params["biz_content"][0]))
print("notify_url:", unquote_plus(params["notify_url"][0]))

重点检查以下字段:

app_id
biz_content
charset
method
notify_url
sign_type
timestamp
version
sign

当前字符串解码后的主要内容如下:

method: alipay.trade.app.pay
charset: utf-8
sign_type: RSA2
version: 1.0
timestamp: 2022-04-15 21:39:55
notify_url:
https://www.starseed07.com/https://www.starseed07.com/api/payments/alipay/notify-url/

biz_content 解码后为:

{
  "subject": "starseed-10min",
  "out_trade_no": "202204152136422609339",
  "total_amount": 6,
  "product_code": "QUICK_MSECURITY_PAY"
}

从现有内容来看,biz_content 的 JSON 结构没有明显语法错误,product_code 也是 App 支付常用的值。首先需要处理的仍是重复拼接的 notify_url。

修正服务端 URL 拼接

常见原因是配置项已经包含完整域名,代码又在前面拼接了一次站点地址。例如:

site_url = "https://www.starseed07.com/"
notify_url = "https://www.starseed07.com/api/payments/alipay/notify-url/"

# 错误:notify_url 已经是绝对地址
final_notify_url = site_url + notify_url

配置方式需要统一。可以直接配置完整地址:

notify_url = (
    "https://www.starseed07.com"
    "/api/payments/alipay/notify-url/"
)

也可以使用相对路径安全拼接:

from urllib.parse import urljoin

site_url = "https://www.starseed07.com/"
notify_path = "api/payments/alipay/notify-url/"

notify_url = urljoin(site_url, notify_path)

assert notify_url == (
    "https://www.starseed07.com/"
    "api/payments/alipay/notify-url/"
)

创建订单前还可以增加校验:

from urllib.parse import urlparse

def validate_notify_url(url: str) -> None:
    parsed = urlparse(url)

    if parsed.scheme not in {"http", "https"}:
        raise ValueError("notify_url 必须使用 http 或 https")

    if not parsed.netloc:
        raise ValueError("notify_url 缺少域名")

    if "http://" in parsed.path or "https://" in parsed.path:
        raise ValueError("notify_url 路径中包含重复拼接的完整 URL")

validate_notify_url(notify_url)

使用 python-alipay-sdk 重新生成订单参数

修正回调地址后,重新调用 SDK 生成支付字符串:

from alipay import AliPay

alipay = AliPay(
    appid="2021000119627334",
    app_notify_url=None,
    app_private_key_string=APP_PRIVATE_KEY,
    alipay_public_key_string=ALIPAY_PUBLIC_KEY,
    sign_type="RSA2",
    debug=False,
)

notify_url = (
    "https://www.starseed07.com"
    "/api/payments/alipay/notify-url/"
)

order_string = alipay.api_alipay_trade_app_pay(
    out_trade_no="202204152136422609339",
    total_amount="6.00",
    subject="starseed-10min",
    notify_url=notify_url,
)

print(order_string)

不同版本的 python-alipay-sdk 可能使用不同的初始化参数或方法签名,以上写法应以项目实际安装的 3.0.4 版本接口为准。不要手工修改最终字符串,而要把正确的 notify_url 传给 SDK,由 SDK 重新编码和签名。

金额建议使用字符串:

total_amount="6.00"

这样可以避免业务代码中的浮点数精度或序列化格式问题。

客户端应原样传递订单字符串

服务端返回的整个 order_string 应直接交给 Tobias。客户端不要做以下处理:

  • 不要再次对整个字符串进行 URL 编码。
  • 不要先 URL 解码再重新拼接。
  • 不要将参数转成 Map 后改变参数顺序。
  • 不要替换 +、%2B、%3D 等字符。
  • 不要在客户端修改 notify_url、金额或订单号。

示意代码:

final String orderInfo = response.data['order_string'];

// 按 Tobias 2.2.0 在项目中的实际 API 调用。
// 核心要求是将 orderInfo 原样传入,不再编码或拼接。
final result = await tobias.pay(orderInfo);

如果项目的导入方式或方法名称不同,应根据 Tobias 2.2.0 的实际接口调整,但传入的内容必须是服务端 SDK 生成的完整订单字符串。

继续排查签名问题

修复 notify_url 后如果仍然报错,再检查以下内容:

  1. 服务端签名使用的应用私钥是否属于 app_id=2021000119627334 对应的支付宝应用。
  2. 支付宝开放平台配置的应用公钥是否与当前私钥配套。
  3. sign_type 是否与签名算法一致。这里声明的是 RSA2,对应 SHA256WithRSA。
  4. 是否混用了支付宝公钥和应用公钥。验签时通常需要支付宝公钥。
  5. 生产环境和沙箱环境的 App ID、密钥及网关配置是否混用。
  6. 该应用是否已正确开通 App 支付能力。
  7. 服务端生成签名后,订单字符串是否被网关、JSON 序列化过程或客户端代码改写。

还要留意 sign 中的特殊字符,例如:

+
/
=

它们在查询字符串中通常会被编码为:

%2B
%2F
%3D

这是正常的。常见问题是订单字符串被重复编码,或者 %2B 被错误还原为 +,之后又被表单解析为空格。

推荐的传输方式

服务端可以将完整订单字符串放在 JSON 字段中返回:

{
  "order_string": "app_id=...&biz_content=...&sign=..."
}

Flutter 读取该字段后,直接传给支付插件:

final orderInfo = json['order_string'] as String;

不建议把订单字符串作为另一个 URL 的查询参数返回。如果业务上必须这样传输,还需要处理外层 URL 编码,很容易造成二次编码。

最终检查顺序

按以下顺序排查:

  1. 将 notify_url 修正为只包含一个域名的完整 HTTPS 地址。
  2. 废弃当前已经生成的订单字符串。
  3. 使用修正后的参数重新调用 python-alipay-sdk。
  4. 确认 SDK 完成签名后,没有其他代码修改订单字符串。
  5. Flutter 端将字符串原样传给 Tobias。
  6. 如果仍然失败,再核对 App ID、RSA2 密钥、应用环境和支付能力配置。

当前参数中可以确定的异常是 notify_url 重复拼接,应先修复这个问题。但只看这段字符串,无法离线确认签名和应用配置是否正确。签名是否有效,还需要结合应用密钥和支付宝侧配置进行验证。

备注:内容仅供参考。