手机网站支付 API 调用 certificateExecute 报错
结论
alipay.trade.wap.pay 是页面类接口。正常情况下,它返回的是用于跳转到支付宝收银台的 HTML,而不是 JSON。
调用 alipayClient.certificateExecute(request) 时,SDK 会按普通 API 响应解析返回内容。如果内容以 <html>、<form> 等字符开头,JSON 解析器会直接在第 1 列报错:
java.lang.IllegalArgumentException: expected value at column 1
手机网站支付应使用 pageExecute(request)。取得 HTML 后,将其原样写入 HTTP 响应,由浏览器跳转到支付宝收银台。
正确调用方式
AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
request.setReturnUrl("https://www.example.com/pay/return");
request.setNotifyUrl("https://www.example.com/pay/notify");
AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
model.setOutTradeNo("ORDER_202609130001");
model.setTotalAmount("0.01");
model.setSubject("测试订单");
model.setProductCode("QUICK_WAP_WAY");
request.setBizModel(model);
String form = alipayClient.pageExecute(request).getBody();
在 Servlet 中,可以直接将返回内容写给浏览器:
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write(form);
response.getWriter().flush();
使用 Spring MVC 时,也可以直接返回 HTML:
@PostMapping(value = "/pay", produces = "text/html;charset=UTF-8")
@ResponseBody
public String pay() throws AlipayApiException {
AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
request.setReturnUrl("https://www.example.com/pay/return");
request.setNotifyUrl("https://www.example.com/pay/notify");
AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
model.setOutTradeNo("ORDER_202609130001");
model.setTotalAmount("0.01");
model.setSubject("测试订单");
model.setProductCode("QUICK_WAP_WAY");
request.setBizModel(model);
return alipayClient.pageExecute(request).getBody();
}
是否使用证书模式,取决于 alipayClient 的初始化配置,并不意味着页面支付必须调用 certificateExecute()。只要客户端已经正确配置应用证书、支付宝公钥证书和支付宝根证书,调用 pageExecute() 时仍会使用这些证书配置。
排查步骤
1. 确认请求类型
确认请求对象是:
AlipayTradeWapPayRequest
接口名称是:
alipay.trade.wap.pay
这类接口用于生成收银台页面,因此应该调用 pageExecute()。
2. 检查实际返回内容
如果改用 pageExecute() 后仍然报错,可以记录 HTTP 状态码、响应头,以及响应正文开头的一小段内容。不要将完整的支付表单、签名或敏感参数写入公开日志。
响应以以下内容开头时,说明返回的是页面:
<form
或者:
<!DOCTYPE html>
如果收到的是网关错误页、代理错误页或登录页,则要继续检查网关地址和网络链路。
3. 检查支付宝网关地址
生产环境通常使用支付宝正式网关,沙箱环境使用对应的沙箱网关。沙箱应用、正式应用和网关地址不能混用。
还要检查配置中是否误填了业务页面地址、代理地址或其他非 API 网关地址。网关地址错误时,可能返回 HTML 错误页,从而引发同样的 JSON 解析异常。
4. 检查证书配置
使用证书模式时,以下配置必须相互匹配:
appId- 应用私钥
- 应用公钥证书
- 支付宝公钥证书
- 支付宝根证书
- 正式环境或沙箱环境
不要将证书文件与普通公钥模式的字符串配置混用。具体的初始化参数取决于支付宝 Java SDK 版本,应以对应版本提供的构造方法或配置对象为准。
5. 排除代理和拦截器影响
如果请求经过 Nginx、API 网关、公司代理或统一认证系统,需要确认中间层没有将支付宝响应替换为:
- 502/504 错误页面;
- 登录认证页面;
- WAF 拦截页面;
- 自定义异常页面。
这些页面也不是 JSON,因此同样可能触发 expected value at column 1。
注意事项
return_url 只用于支付完成后的浏览器跳转,不能作为判断订单支付成功的唯一依据。订单状态应以支付宝发送到 notify_url 的异步通知为主,同时校验签名、商户订单号、金额、应用标识等字段。
不要自行解析或修改 pageExecute() 返回的 HTML 表单。通常应将它原样输出给浏览器,否则可能破坏隐藏字段、签名参数或自动提交逻辑。
示例中的响应类型应写为:
AlipayTradeWapPayResponse
如果业务只需要输出收银台页面,也可以直接使用:
String form = alipayClient.pageExecute(request).getBody();
这种写法更符合手机网站支付接口的用途。
备注:内容仅供参考。
