PAYATHON 2026

Python 支付宝订单加签遇到 UnicodeDecodeError

支付阿杰

结论

问题不在 charset,而在于调用的方法不对。

使用 AlipayTradeAppPayRequest 生成 App 支付订单串时,应调用:

client.sdk_execute(payreq)

而不是:

client.execute(payreq)

sdk_execute() 会在本地组装参数、完成 RSA2 签名,并返回可以直接交给支付宝客户端 SDK 的订单字符串。execute() 会向支付宝网关发送服务端请求,再尝试按 UTF-8 解码响应内容,所以代码才会在 __parse_response() 中触发 UnicodeDecodeError。

正确的实现方式

下面是支付宝 App 支付的示例:

from alipay.aop.api.AlipayClientConfig import AlipayClientConfig
from alipay.aop.api.DefaultAlipayClient import DefaultAlipayClient
from alipay.aop.api.domain.AlipayTradeAppPayModel import AlipayTradeAppPayModel
from alipay.aop.api.request.AlipayTradeAppPayRequest import AlipayTradeAppPayRequest


config = AlipayClientConfig()
config.server_url = "https://openapi.alipay.com/gateway.do"
config.app_id = "你的 APP_ID"
config.app_private_key = """-----BEGIN PRIVATE KEY-----
你的应用私钥
-----END PRIVATE KEY-----"""
config.alipay_public_key = """-----BEGIN PUBLIC KEY-----
支付宝公钥
-----END PUBLIC KEY-----"""
config.charset = "utf-8"
config.sign_type = "RSA2"

client = DefaultAlipayClient(
    alipay_client_config=config,
    logger=None
)

model = AlipayTradeAppPayModel()
model.subject = "订单标题"
model.out_trade_no = "202609090001"
model.total_amount = "0.01"
model.product_code = "QUICK_MSECURITY_PAY"
model.timeout_express = "30m"

payreq = AlipayTradeAppPayRequest(biz_model=model)
payreq.notify_url = "https://example.com/alipay/notify"

# 生成已经签名的 App 支付订单串,不向支付宝网关发送请求
order_string = client.sdk_execute(payreq)

print(order_string)

服务端只需把 order_string 返回给 App,客户端再将这段字符串交给支付宝 App SDK 发起支付。

execute() 和 sdk_execute() 的区别

sdk_execute()

这个方法用于生成客户端调用参数,例如 App 支付:

order_string = client.sdk_execute(payreq)

它会组装公共参数和业务参数,完成 URL 编码,使用应用私钥进行 RSA2 签名,然后返回支付订单字符串。整个过程不会访问支付宝网关,也不需要解析网关响应。

execute()

这个方法用于服务端直接调用支付宝 OpenAPI,例如查询订单或申请退款:

response = client.execute(request)

它会访问支付宝网关,并将响应内容解码、解析为 JSON。当前异常就发生在解码阶段:

response_str = response_str.decode(self.__config.charset)

因此,反复修改 charset 无法解决方法调用错误。

如果服务端接口也出现相同错误

查询订单、退款等接口本来就应该使用 execute()。如果调用这些接口时仍然报错,需要检查收到的原始响应。

支付宝 OpenAPI 的正常响应通常是与配置字符集一致的 JSON。如果实际收到的是 GBK 页面、代理错误页或其他二进制内容,使用 UTF-8 强制解码就会失败。

可以按以下方向排查:

  1. 确认 server_url 是否正确:
# 正式环境
https://openapi.alipay.com/gateway.do

# 沙箱环境
https://openapi.alipaydev.com/gateway.do
  1. 检查请求是否经过公司代理、抓包工具、网关或 WAF。
  2. 确认返回内容是否为 HTML 错误页,而不是支付宝 JSON。
  3. 确认安装的 SDK 来自支付宝官方发布渠道。
  4. 检查应用私钥、支付宝公钥和签名类型是否匹配。
  5. 检查是否混用了沙箱应用信息和正式环境网关。

调试时,可以临时在 SDK 解码前打印部分原始数据,确认实际返回的内容:

print(repr(response_str[:500]))

这段代码只适合调试。不要用下面的方式绕过解码错误:

response_str.decode("utf-8", errors="ignore")

忽略非法字节可能会破坏 JSON 内容或签名验签结果。

关于官方 Python 示例

支付宝开放平台提供 Python SDK,代码中的 alipay.aop.api 是常见的模块结构。在官方 SDK 的说明或示例中,生成 App 支付订单通常使用 sdk_execute(),查询、退款等服务端 OpenAPI 则使用 execute()。

开放平台的文档入口和 SDK 发布方式可能会调整。下载时应以支付宝开放平台当前提供的 SDK、示例或 API 调试工具为准,避免使用长期未维护的第三方封装。

对于当前代码,把:

response_content = client.execute(payreq)

改为:

response_content = client.sdk_execute(payreq)

通常就能解决问题。

备注:内容仅供参考。