如何将支付宝APP原生支付链接转换为H5支付链接?
结论
缺少商户签约信息和私钥时,无法把这段 APP 原生支付参数直接拼接成可用的支付宝 H5 支付链接。
APP 支付和手机网站支付是两个不同的支付产品,接口、请求参数和签名内容都不相同。原有 sign 只对签名时使用的参数集合有效。一旦修改接口名称、参数或跳转地址,验签就会失败。
正确的处理方式是由水果公司的服务端开通手机网站支付能力,使用自己的支付宝商户应用凭证,重新调用 alipay.trade.wap.pay。如果你不是该商户,也没有获得商户授权,就无法合法、可靠地为这个订单生成 H5 支付请求。
为什么不能直接转换
示例内容更接近旧版 APP 支付订单串,其中包含:
partnerseller_idpayment_typetotal_feesign_type=RSAsign
sign 是商户使用私钥对指定参数进行签名后生成的。支付宝会用对应的公钥验证订单是否被修改。只要替换、增加、删除或重新编码参数,原签名通常就会失效。
现在的手机网站支付一般调用:
alipay.trade.wap.pay
该接口通常需要 app_id、method、timestamp、biz_content、sign_type 和 sign 等公共参数,并且必须重新签名。仅把原订单串的协议头从:
fruit://alipay/...
改成某个 HTTPS 地址,并不能完成转换。
另外,H5 支付返回的通常是自动提交的 HTML 表单或跳转页面,不能简单地把它当成一个长期有效的静态支付链接。
正确处理流程
1. 确认商户已经开通手机网站支付
商户需要在支付宝开放平台创建并配置应用,同时开通对应的手机网站支付能力。签约条件和配置项可能随支付宝平台调整,应以商户后台当前显示的要求为准。
服务端至少需要准备:
app_id- 商户应用私钥
- 支付宝公钥,或支付宝公钥证书
- 支付异步通知地址
notify_url - 支付完成后的页面返回地址
return_url
旧订单中的 partner、seller_id 和 sign,不足以发起新的 H5 支付。
2. 在服务端重新创建支付订单
业务系统应根据自己的商品和订单记录重新生成参数,例如:
{
"out_trade_no": "FB35454798708",
"total_amount": "70.00",
"subject": "购买70元水果",
"product_code": "QUICK_WAP_WAY"
}
不要直接采用客户端传入的金额、商品名称或收款方信息。服务端应从数据库读取订单金额,并检查订单状态和所属用户。
out_trade_no 必须符合商户系统的唯一性要求。如果原订单已经支付、关闭或正在支付,应根据当前业务状态处理,不能直接重复发起。
3. 调用手机网站支付接口
下面是常见的 Java 服务端写法。支付宝 Java SDK 的类名和构造方式可能随版本变化,接入时应以所用版本的官方文档为准。
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.alipay.api.response.AlipayTradeWapPayResponse;
public class AlipayWapPayService {
public String createPayForm() throws Exception {
String gatewayUrl = "https://openapi.alipay.com/gateway.do";
String appId = System.getenv("ALIPAY_APP_ID");
String merchantPrivateKey =
System.getenv("ALIPAY_MERCHANT_PRIVATE_KEY");
String alipayPublicKey =
System.getenv("ALIPAY_PUBLIC_KEY");
AlipayClient alipayClient = new DefaultAlipayClient(
gatewayUrl,
appId,
merchantPrivateKey,
"json",
"UTF-8",
alipayPublicKey,
"RSA2"
);
AlipayTradeWapPayRequest request =
new AlipayTradeWapPayRequest();
request.setNotifyUrl(
"https://merchant.example.com/api/alipay/notify"
);
request.setReturnUrl(
"https://merchant.example.com/pay/result"
);
request.setBizContent("""
{
"out_trade_no": "FB35454798708",
"total_amount": "70.00",
"subject": "购买70元水果",
"product_code": "QUICK_WAP_WAY"
}
""");
AlipayTradeWapPayResponse response =
alipayClient.pageExecute(request);
if (!response.isSuccess()) {
throw new IllegalStateException(
"创建支付宝H5支付请求失败:"
+ response.getSubCode()
+ " "
+ response.getSubMsg()
);
}
return response.getBody();
}
}
response.getBody() 一般是支付宝生成的 HTML 表单。服务端可以将它作为 text/html 返回给浏览器:
@GetMapping(
value = "/pay/alipay",
produces = "text/html;charset=UTF-8"
)
@ResponseBody
public String pay() throws Exception {
return alipayWapPayService.createPayForm();
}
浏览器加载该响应后,会进入支付宝的 H5 支付流程。商户私钥不能放在 Android、JavaScript 或其他客户端程序中。
4. 通过异步通知确认支付结果
用户跳转到 return_url,并不代表订单已经支付成功。业务系统必须验证支付宝发送到 notify_url 的异步通知,包括:
- 验证通知签名;
- 核对商户应用或收款方信息;
- 核对
out_trade_no; - 核对订单金额;
- 检查交易状态;
- 做幂等处理,避免重复发货。
只有验签和业务数据校验全部通过后,才能将订单标记为已支付。
如果只能拿到这段原生链接
如果只有这段链接,程序最多只能解析订单号、金额和标题等普通字段,无法据此生成支付宝认可的 H5 支付请求。
可以采用以下方式处理:
- 联系原商户,请其服务端提供正规的 H5 下单接口;
- 让原商户在支付宝开放平台配置手机网站支付,并重新生成请求;
- 如果只需打开原 APP 支付流程,继续使用原商户提供且确认有效的 APP 支付方案,不要尝试更改支付渠道。
即使可以从旧参数中读取 out_trade_no 和 total_fee,也不能复用原来的 sign。新的 H5 请求必须由实际收款商户重新签名。
注意事项
- 示例中包含完整手机号等个人信息,不建议将其放入
subject、URL 或可能记录到日志的参数中。支付标题可以改为“购买水果”等非敏感描述。 notify_url必须是支付宝服务器可以访问的 HTTPS 地址,并应做好验签、幂等和重复通知处理。- 私钥只能保存在商户服务端。建议使用密钥管理系统或受控环境变量,不要将私钥写死在源码中。
- 不要通过替换协议头、复制
sign或修改查询参数来“转换”支付方式。这种做法无法通过验签,还可能导致订单冒用、金额篡改或收款方错误。 - 如果没有原商户的授权和支付凭证,应停止转换操作,请商户提供新的 H5 收银台地址。
备注:内容仅供参考。
