支付宝 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 后如果仍然报错,再检查以下内容:
- 服务端签名使用的应用私钥是否属于
app_id=2021000119627334对应的支付宝应用。 - 支付宝开放平台配置的应用公钥是否与当前私钥配套。
sign_type是否与签名算法一致。这里声明的是RSA2,对应 SHA256WithRSA。- 是否混用了支付宝公钥和应用公钥。验签时通常需要支付宝公钥。
- 生产环境和沙箱环境的 App ID、密钥及网关配置是否混用。
- 该应用是否已正确开通 App 支付能力。
- 服务端生成签名后,订单字符串是否被网关、JSON 序列化过程或客户端代码改写。
还要留意 sign 中的特殊字符,例如:
+
/
=
它们在查询字符串中通常会被编码为:
%2B
%2F
%3D
这是正常的。常见问题是订单字符串被重复编码,或者 %2B 被错误还原为 +,之后又被表单解析为空格。
推荐的传输方式
服务端可以将完整订单字符串放在 JSON 字段中返回:
{
"order_string": "app_id=...&biz_content=...&sign=..."
}
Flutter 读取该字段后,直接传给支付插件:
final orderInfo = json['order_string'] as String;
不建议把订单字符串作为另一个 URL 的查询参数返回。如果业务上必须这样传输,还需要处理外层 URL 编码,很容易造成二次编码。
最终检查顺序
按以下顺序排查:
- 将
notify_url修正为只包含一个域名的完整 HTTPS 地址。 - 废弃当前已经生成的订单字符串。
- 使用修正后的参数重新调用
python-alipay-sdk。 - 确认 SDK 完成签名后,没有其他代码修改订单字符串。
- Flutter 端将字符串原样传给 Tobias。
- 如果仍然失败,再核对 App ID、RSA2 密钥、应用环境和支付能力配置。
当前参数中可以确定的异常是 notify_url 重复拼接,应先修复这个问题。但只看这段字符串,无法离线确认签名和应用配置是否正确。签名是否有效,还需要结合应用密钥和支付宝侧配置进行验证。
备注:内容仅供参考。
