支付宝PC端网页扫码支付提示invalid-format如何解决?
结论
invalid-format 表示支付宝网关收到的请求中,至少有一个参数不符合接口格式要求。错误页不会指出具体字段。在 PC 网站支付场景中,建议先检查以下内容:
biz_content是否为合法 JSON,是否发生了重复转义或重复 URL 编码total_amount、timestamp、timeout_express等字段的格式是否正确method、product_code、charset、version是否符合电脑网站支付接口的要求- SDK 返回的
<form>是否被模板引擎、JSON 序列化或前端代码改写 - 修改参数后是否重新生成了签名
使用官方 SDK 时,建议直接输出 pageExecute() 返回的完整 HTML,不要自行拆解、拼接或再次编码表单。
常见的无效数据格式
1. biz_content 不是合法 JSON
alipay.trade.page.pay 的业务参数都放在 biz_content 中。以下情况可能引发格式错误:
- 使用单引号拼接 JSON
- JSON 末尾带有多余逗号
- 金额等字符串没有正确加引号
- 中文、双引号或反斜杠转义错误
- JSON 被 HTML 转义为
" - 整段 JSON 又经过一次 URL 编码
- 把 JSON 字符串再次序列化,变成双层字符串
正确结构示例:
{
"out_trade_no": "ORDER202609090001",
"product_code": "FAST_INSTANT_TRADE_PAY",
"total_amount": "99.00",
"subject": "订单支付"
}
不要手工拼接 JSON。可以使用 SDK 提供的业务模型,也可以通过成熟的 JSON 序列化库生成。
2. total_amount 格式错误
金额应使用十进制字符串,例如:
0.01
99.00
128.50
以下写法通常不符合要求:
¥99.00
99元
1,299.00
99.001
NaN
null
业务代码中也不要先用 double 计算金额,再直接转成字符串,否则可能得到 99.00000000003 之类的结果。Java 可以使用 BigDecimal:
BigDecimal amount = new BigDecimal("99.00");
model.setTotalAmount(amount.setScale(2, RoundingMode.HALF_UP).toPlainString());
金额的实际精度和取值范围应以当前接入接口的参数文档为准。
3. 时间参数格式不正确
公共参数 timestamp 通常使用以下格式:
yyyy-MM-dd HH:mm:ss
例如:
2026-09-09 14:30:00
不要传入 Unix 时间戳、ISO 8601 时间或带毫秒的时间,例如:
1788935400
2026-09-09T14:30:00+08:00
2026-09-09 14:30:00.123
设置 timeout_express 时,应使用接口支持的相对时间格式,例如:
30m
1h
不要写成 "30分钟"、"1800" 或自定义日期字符串。具体可用格式以当前接口文档为准。
4. 混用了其他支付产品的参数
电脑网站支付通常使用:
method=alipay.trade.page.pay
product_code=FAST_INSTANT_TRADE_PAY
version=1.0
format=json
charset=UTF-8
sign_type=RSA2
如果项目还接入了手机网站支付、当面付或旧版即时到账接口,需要确认代码没有复用其他接口的 method、product_code 或业务参数结构。不同支付产品的参数不能直接混用。
5. 表单被二次处理
SDK 返回的通常是一段可以直接提交的 HTML 表单。以下操作容易破坏其中的隐藏字段:
- 把表单放入 JSON 响应,再交给前端取出
- 对整个表单进行 HTML 转义
- 使用模板语法重新渲染
<input>的值 - 对参数再次调用
encodeURIComponent - 由前端读取隐藏字段并重新组装请求
- 修改字段值后继续使用原来的
sign
服务端可以直接返回表单:
AlipayClient alipayClient = new DefaultAlipayClient(
gatewayUrl,
appId,
merchantPrivateKey,
"json",
"UTF-8",
alipayPublicKey,
"RSA2"
);
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
request.setReturnUrl(returnUrl);
request.setNotifyUrl(notifyUrl);
AlipayTradePagePayModel model = new AlipayTradePagePayModel();
model.setOutTradeNo("ORDER202609090001");
model.setProductCode("FAST_INSTANT_TRADE_PAY");
model.setTotalAmount("99.00");
model.setSubject("订单支付");
request.setBizModel(model);
String form = alipayClient.pageExecute(request).getBody();
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write(form);
不要把 form 包装成下面这样的 JSON:
{
"code": 0,
"data": "<form>...</form>"
}
如果业务架构要求由前端发起跳转,可以让后端提供一个专门的支付入口。浏览器访问该入口后,由后端直接输出支付宝表单。
排查步骤
1. 检查浏览器实际提交的请求
打开浏览器开发者工具,在 Network 中找到提交给支付宝网关的请求,查看最终发送的表单字段,重点检查:
app_id
method
format
charset
sign_type
timestamp
version
sign
biz_content
应检查浏览器最终发出的数据,不能只看后端日志中的原始对象。
2. 单独校验 biz_content
将请求中的 biz_content 正常 URL 解码一次,再交给 JSON 解析器验证。解码结果应该是一个 JSON 对象:
{"out_trade_no":"ORDER202609090001","product_code":"FAST_INSTANT_TRADE_PAY","total_amount":"99.00","subject":"订单支付"}
如果得到下面这种形式,通常说明 JSON 被重复序列化了:
"{\"out_trade_no\":\"ORDER202609090001\",...}"
如果内容中出现大量 %22、%257B 或 ",应检查 URL 编码和 HTML 转义分别执行了多少次。
3. 使用最小参数重新测试
先只保留必需的业务参数:
{
"out_trade_no": "唯一订单号",
"product_code": "FAST_INSTANT_TRADE_PAY",
"total_amount": "0.01",
"subject": "测试订单"
}
最小请求成功后,再逐项加入 body、timeout_express、passback_params 等可选字段。这样更容易确定是哪个字段导致了错误。
passback_params 的处理比较特殊。使用该字段时,应按接口要求编码,并确保参与签名的值与最终提交的值完全一致。
4. 确认签名前后的参数完全一致
签名生成后,所有参与签名的参数都不能再修改,包括:
- JSON 中的空格和转义形式
- 字符编码
- 金额表示
- 回调地址
- 订单标题
biz_content的完整字符串
只要参数发生变化,就必须重新生成 sign。如果字符集声明为 UTF-8,生成签名和发送请求时也应使用 UTF-8。
5. 核对环境配置
确认沙箱环境和正式环境没有混用,检查:
- 网关地址
app_id- 应用私钥
- 支付宝公钥
- 应用签约产品
环境或密钥配置错误通常会表现为验签失败、权限异常或应用状态错误。不过在排查 invalid-format 时,也应同时核对这些配置,避免多个问题叠加。
仍然无法定位时需要保留的信息
提交技术支持前,可以记录以下内容:
- 支付宝返回的错误代码和请求时间
- 网关响应中的请求标识,例如页面提供的
request_id或类似字段 - 脱敏后的公共参数
- 正常解码一次后的
biz_content - SDK 名称和实际使用版本
- 当前使用的是沙箱环境还是正式环境
- 浏览器实际发送的请求参数
不要提交应用私钥,也不要在公开日志中暴露完整签名、用户信息或敏感的回调参数。错误页只能说明请求中的数据格式不符合要求,具体原因仍要根据实际提交到网关的参数判断。
备注:内容仅供参考。
