APP支付服务端Python接入如何获取orderStr
结论
Python 服务端可以为 alipay.trade.app.pay 生成 orderStr。即使接口文档没有提供 Python 示例,也不影响接入。orderStr 本质上是一组按照支付宝开放平台规则组装、使用应用私钥签名并完成 URL 编码的请求参数。
服务端需要完成以下操作:
- 组装公共请求参数和
biz_content。 - 使用应用私钥进行 RSA2 签名。
- 对全部参数进行 URL 编码,得到
orderStr。 - 将
orderStr原样返回给 APP。 - APP 调用支付宝客户端 SDK 发起支付。
支付结果不能只看 APP 的同步返回。服务端还要通过 notify_url 接收异步通知,并使用支付宝公钥验签。
关键参数
公共请求参数通常包括:
| 参数 | 示例 | 说明 |
|---|---|---|
app_id | 202100xxxxxxxxxx | 支付宝开放平台应用 ID |
method | alipay.trade.app.pay | 固定值 |
charset | utf-8 | 建议固定使用 UTF-8 |
sign_type | RSA2 | 建议使用 RSA2 |
timestamp | 2026-09-09 10:30:00 | 格式为 yyyy-MM-dd HH:mm:ss |
version | 1.0 | 接口版本 |
notify_url | https://example.com/alipay/notify | 支付宝异步通知地址 |
biz_content | JSON 字符串 | 业务请求参数 |
sign | Base64 字符串 | 应用私钥签名结果 |
biz_content 常用参数如下:
{
"subject": "会员充值",
"out_trade_no": "ORDER202609090001",
"total_amount": "99.00",
"product_code": "QUICK_MSECURITY_PAY"
}
各参数的含义:
subject:订单标题。out_trade_no:商户订单号,必须在商户系统内唯一。total_amount:订单金额,单位为元,建议使用字符串传递。product_code:APP 支付通常填写QUICK_MSECURITY_PAY。body、timeout_express等参数可根据业务需要添加。
Python 生成 orderStr
下面的代码不依赖特定的支付宝 SDK,而是直接按照 RSA2 签名规则生成 orderStr。示例使用 cryptography 库:
pip install cryptography
import base64
import json
from datetime import datetime
from urllib.parse import urlencode
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
def rsa2_sign(content: str, app_private_key: str) -> str:
"""
使用应用私钥执行 SHA256WithRSA 签名,
并返回 Base64 编码后的签名字符串。
"""
private_key = serialization.load_pem_private_key(
app_private_key.encode("utf-8"),
password=None,
)
signature = private_key.sign(
content.encode("utf-8"),
padding.PKCS1v15(),
hashes.SHA256(),
)
return base64.b64encode(signature).decode("utf-8")
def build_order_str(
app_id: str,
app_private_key: str,
notify_url: str,
out_trade_no: str,
subject: str,
total_amount: str,
) -> str:
biz_content = {
"subject": subject,
"out_trade_no": out_trade_no,
"total_amount": total_amount,
"product_code": "QUICK_MSECURITY_PAY",
}
params = {
"app_id": app_id,
"method": "alipay.trade.app.pay",
"charset": "utf-8",
"sign_type": "RSA2",
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"version": "1.0",
"notify_url": notify_url,
"biz_content": json.dumps(
biz_content,
ensure_ascii=False,
separators=(",", ":"),
),
}
# 待签名字符串:排除 sign,按参数名升序排列。
sign_content = "&".join(
f"{key}={params[key]}"
for key in sorted(params)
if params[key] is not None and params[key] != ""
)
params["sign"] = rsa2_sign(sign_content, app_private_key)
# 签名完成后再对参数名和参数值进行 URL 编码。
return urlencode(
sorted(params.items()),
encoding="utf-8",
errors="strict",
)
调用示例:
APP_PRIVATE_KEY = """-----BEGIN PRIVATE KEY-----
你的应用私钥内容
-----END PRIVATE KEY-----"""
order_str = build_order_str(
app_id="202100xxxxxxxxxx",
app_private_key=APP_PRIVATE_KEY,
notify_url="https://example.com/api/alipay/notify",
out_trade_no="ORDER202609090001",
subject="会员充值",
total_amount="99.00",
)
print(order_str)
生成的结果大致如下:
app_id=202100xxxxxxxxxx&biz_content=%7B...%7D&charset=utf-8&method=alipay.trade.app.pay¬ify_url=https%3A%2F%2Fexample.com%2Fapi%2Falipay%2Fnotify&sign=...&sign_type=RSA2×tamp=2026-09-09+10%3A30%3A00&version=1.0
服务端接口可以把它返回给客户端:
from flask import Flask, jsonify
app = Flask(__name__)
@app.post("/api/payment/alipay")
def create_alipay_order():
# 实际项目中应先在数据库创建订单,
# out_trade_no 和金额必须从服务端可信数据中取得。
order_str = build_order_str(
app_id="202100xxxxxxxxxx",
app_private_key=APP_PRIVATE_KEY,
notify_url="https://example.com/api/alipay/notify",
out_trade_no="ORDER202609090001",
subject="会员充值",
total_amount="99.00",
)
return jsonify({
"orderStr": order_str
})
客户端拿到 orderStr 后,应把整个字符串直接交给支付宝 APP SDK,不要自行拆分、重新排序,也不要再次进行 URL 编码。
使用支付宝 Python SDK 时的处理方式
如果选用的 Python SDK 已经实现 alipay.trade.app.pay,基本流程不变:
biz_content = {
"subject": "会员充值",
"out_trade_no": "ORDER202609090001",
"total_amount": "99.00",
"product_code": "QUICK_MSECURITY_PAY",
}
接着通过 SDK 中用于生成 APP 支付请求字符串的方法取得结果。不同 Python SDK 的包名、初始化参数和方法名可能不一样,不能直接照搬 Java SDK 的 sdkExecute()。使用前应查看所用 SDK 当前版本的说明,并确认:
- 调用的方法是
alipay.trade.app.pay。 - 签名方式是 RSA2,也就是
SHA256WithRSA。 - 返回值是可以直接交给客户端 SDK 的完整请求字符串,而不是普通接口响应 JSON。
- 使用应用私钥签名,而不是支付宝公钥。
- SDK 没有重复编码
biz_content或整个请求字符串。
如果无法确认第三方 SDK 的维护状态,可以直接使用前面的通用方式生成 orderStr。这样通常也更方便排查签名和编码问题。
容易出错的地方
私钥和公钥不要混用
生成 orderStr 时要使用应用私钥。处理支付宝异步通知时,要使用支付宝公钥验证 sign。
证书模式还会涉及应用公钥证书、支付宝公钥证书和支付宝根证书,公共参数中也可能需要加入证书序列号。上面的示例使用普通公钥模式。如果应用配置的是证书模式,应按照证书模式当前的接入规范处理,不能只替换密钥文件。
签名前不能进行 URL 编码
正确顺序如下:
原始参数值
→ 参数名排序并拼接
→ RSA2 签名
→ 加入 sign
→ 对完整参数进行 URL 编码
→ 得到 orderStr
如果先编码 biz_content、notify_url 等字段,再使用编码后的内容签名,通常会出现 isv.invalid-signature 或客户端支付失败。
金额必须由服务端决定
不要直接信任客户端提交的商品名称和支付金额。服务端应根据商品 ID、订单 ID 等信息重新查询实际金额,再生成 orderStr,否则客户端可能篡改金额。
商户订单号必须唯一
out_trade_no 应由服务端生成并持久化。用户重复点击支付时,可以根据业务策略复用尚未关闭的订单,也可以生成新的唯一订单号,但不能随意重复提交已经支付成功的订单号。
异步通知必须验签
notify_url 必须是支付宝服务器能够访问的 HTTPS 地址。收到通知后,至少要完成以下检查和处理:
- 使用支付宝公钥验证通知签名。
- 检查
app_id是否属于当前应用。 - 检查
seller_id是否为预期收款账号。 - 检查
out_trade_no是否存在。 - 检查
total_amount是否与本地订单一致。 - 根据
trade_status幂等更新订单状态。 - 按照支付宝要求返回成功响应。
客户端返回的”支付成功”只能用于界面提示,不能直接作为发货或充值的依据。
不要记录完整敏感信息
应用私钥不能放进客户端,也不要提交到代码仓库。生产环境应通过密钥管理服务或受保护的环境配置加载私钥。日志可以记录商户订单号和接口错误信息,但不应输出应用私钥或其他敏感凭据。
备注:内容仅供参考。
