支付宝对接沙箱支付时支付页面打不开并提示SYSTEM_ERROR
结论
SYSTEM_ERROR 是支付宝返回的通用系统异常。仅凭支付页面上的错误码,无法确定具体原因。在沙箱环境中,常见问题包括:
- 沙箱网关、沙箱
app_id和沙箱密钥没有配套使用; - 请求签名错误,或混淆了应用公钥与支付宝公钥;
alipay.trade.page.pay的必填参数缺失或格式不正确;- 服务端没有将支付宝 SDK 返回的 HTML 表单正确输出到浏览器;
- 支付宝沙箱服务暂时异常。
排查时,先核对环境和密钥,再记录完整的请求参数及支付宝返回内容。不要仅凭页面上的”系统有点儿忙”,就认定是支付宝服务器故障。
1. 检查是否使用了沙箱网关
电脑网站支付的沙箱网关通常应配置为:
https://openapi.alipaydev.com/gateway.do
正式环境网关为:
https://openapi.alipay.com/gateway.do
沙箱 app_id、沙箱应用私钥、沙箱支付宝公钥必须与沙箱网关配套使用。常见错误有:
- 使用沙箱
app_id请求正式网关; - 使用正式应用密钥请求沙箱网关;
- 复制了其他沙箱应用的公钥;
- 修改配置后,正在运行的服务仍在读取旧配置。
发起请求前,可以记录当前使用的网关和 app_id,但不要将私钥写入日志。
2. 核对密钥和签名配置
调用支付宝开放平台 API 时,需要分清以下三种密钥:
- 应用私钥:保存在商户侧,用于生成请求签名;
- 应用公钥:上传到支付宝开放平台;
- 支付宝公钥:由支付宝提供,用于验证支付宝响应和异步通知。
初始化客户端时,应填写”应用私钥”和”支付宝公钥”,不能误将应用公钥填入支付宝公钥的位置。
同时确认以下配置保持一致:
sign_type = RSA2
charset = UTF-8
format = json
如果应用配置使用 RSA2,代码也必须使用 RSA2。密钥中的换行、空格或 PEM 头尾处理不正确,同样可能导致签名失败。
不同 SDK 对密钥格式的要求可能不同。部分 SDK 接受不带 PEM 头尾的密钥正文,部分封装组件则要求完整的 PEM 格式,应以实际使用的 SDK 文档为准。例如:
-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----
应用私钥不能保存在浏览器端,也不能由浏览器端使用。
3. 检查支付请求参数
电脑网站支付通常调用:
alipay.trade.page.pay
核心业务参数示例:
{
"out_trade_no": "ORDER_20260913_0001",
"product_code": "FAST_INSTANT_TRADE_PAY",
"total_amount": "0.01",
"subject": "沙箱支付测试订单"
}
需要重点检查:
out_trade_no在商户系统中是否唯一;total_amount是否为合法的金额字符串;subject是否为空;product_code是否为FAST_INSTANT_TRADE_PAY;- JSON 能否正常解析;
- 参数中是否存在不可见字符或错误编码;
- 订单号是否过长,或包含不合适的特殊字符。
排查时,先使用简单的字母、数字订单号和最小合法金额,减少业务数据造成的干扰:
out_trade_no=TEST202609130001
total_amount=0.01
subject=Sandbox Test
4. 正确输出 SDK 生成的支付表单
alipay.trade.page.pay 的页面支付流程通常不是让前端解析 JSON,而是由 SDK 生成一个自动提交的 HTML 表单,再由服务端将其原样返回给浏览器。
Java 示例:
AlipayClient alipayClient = new DefaultAlipayClient(
"https://openapi.alipaydev.com/gateway.do",
APP_ID,
APP_PRIVATE_KEY,
"json",
"UTF-8",
ALIPAY_PUBLIC_KEY,
"RSA2"
);
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
request.setReturnUrl("https://example.com/alipay/return");
request.setNotifyUrl("https://example.com/alipay/notify");
request.setBizContent("""
{
"out_trade_no": "TEST202609130001",
"product_code": "FAST_INSTANT_TRADE_PAY",
"total_amount": "0.01",
"subject": "Sandbox Test"
}
""");
AlipayTradePagePayResponse response = alipayClient.pageExecute(request);
if (response.isSuccess()) {
String form = response.getBody();
// 将 form 作为 HTML 原样写入 HTTP 响应
} else {
System.err.println("code=" + response.getCode());
System.err.println("subCode=" + response.getSubCode());
System.err.println("msg=" + response.getMsg());
System.err.println("subMsg=" + response.getSubMsg());
}
在 Servlet 中,可以这样返回表单:
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write(form);
response.getWriter().flush();
如果使用 Spring MVC,可以直接返回 HTML:
@GetMapping(value = "/pay", produces = "text/html;charset=UTF-8")
@ResponseBody
public String pay() throws AlipayApiException {
AlipayTradePagePayResponse response = alipayClient.pageExecute(request);
if (!response.isSuccess()) {
throw new IllegalStateException(
"Alipay request failed: code=" + response.getCode()
+ ", subCode=" + response.getSubCode()
+ ", msg=" + response.getMsg()
+ ", subMsg=" + response.getSubMsg()
);
}
return response.getBody();
}
不要再次对 response.getBody() 进行 HTML 转义,否则 <form> 会变成普通文本,页面也无法自动跳转。
5. 查看服务端的完整响应
支付页面只显示 SYSTEM_ERROR 时,还要检查服务端日志中的以下字段:
code
msg
sub_code
sub_msg
request_id
trace_id
实际能获取哪些字段,取决于 SDK 版本和接口返回内容,不一定全部存在。
还应记录以下非敏感信息:
gateway
app_id
method
sign_type
charset
timestamp
out_trade_no
total_amount
SDK 返回的 code、sub_code、msg、sub_msg
以下内容严禁写入日志:
应用私钥
完整签名原文中的敏感业务数据
用户密码
支付密码
完整身份证号或银行卡号
如果服务端已经收到明确的 sub_code,应优先根据 sub_code 排查。页面上的 SYSTEM_ERROR 过于笼统,不能代替接口响应日志。
6. 检查回调地址和网络环境
return_url 用于支付完成后的浏览器跳转,notify_url 用于接收支付宝服务器发送的异步通知。它们通常不是决定支付页面能否打开的唯一因素,但配置异常仍可能影响整个支付流程。
需要确认:
- URL 包含完整的
http://或https://; - URL 中没有空格、中文引号等异常字符;
notify_url可以从公网访问;- HTTPS 证书有效;
- 防火墙或网关没有拦截支付宝请求;
- 回调接口不会被登录验证、CSRF 校验或重定向拦截。
本地地址通常不能直接用作异步通知地址:
http://localhost:8080/alipay/notify
http://127.0.0.1:8080/alipay/notify
不过,异步通知地址暂时无法访问,通常不该作为支付页面完全打不开的首要判断依据。仍应先检查网关、签名和请求参数。
7. 排除浏览器和沙箱账号问题
如果接口已经成功生成支付表单,但跳转后才出现错误,可以继续检查:
- 是否使用了支付宝沙箱提供的买家账号;
- 是否误用正式支付宝账号登录沙箱收银台;
- 浏览器是否拦截表单提交、重定向或 Cookie;
- 页面是否在内嵌 WebView 中打开,从而产生兼容性问题;
- 换用无痕窗口或其他浏览器后,问题是否仍能复现。
沙箱账号、密码和余额,应以支付宝开放平台沙箱页面当前显示的信息为准。
8. 判断是否为沙箱临时异常
完成以下检查后,如果同一套最小请求仍间歇性返回 SYSTEM_ERROR,才更有可能是沙箱环境暂时异常:
- 网关已经确认是沙箱地址;
app_id和密钥来自同一个沙箱应用;- 签名类型和字符编码一致;
- 最小支付参数合法;
- SDK 返回的 HTML 已原样输出;
- 服务端没有返回更具体的
sub_code; - 更换订单号、浏览器和网络后,问题仍然存在。
这时可以稍后重试,并保存错误发生时间、app_id、接口名称、脱敏后的请求参数以及 request_id 等信息,方便进一步定位。重试时必须更换 out_trade_no,或者先确认原订单是否已经创建,以免重复订单干扰判断。
推荐排查顺序
- 确认网关是
https://openapi.alipaydev.com/gateway.do。 - 确认沙箱
app_id、应用私钥和支付宝公钥属于同一个应用。 - 确认使用
RSA2和UTF-8,并检查密钥格式。 - 使用最小参数调用
alipay.trade.page.pay。 - 检查 SDK 返回的
code、sub_code、msg和sub_msg。 - 将 SDK 返回的 HTML 表单原样输出到浏览器。
- 使用沙箱买家账号测试。
- 确认以上配置无误后,再考虑沙箱服务暂时异常。
不要反复修改业务参数来碰运气。服务端的完整响应通常比页面上的 SYSTEM_ERROR 更能说明问题所在。
备注:内容仅供参考。
