PAYATHON 2026

PHP如何接入支付宝H5支付及本地测试

支付阿杰

明确结论

支付宝 H5 支付使用的是手机网站支付(WAP 支付),对应的核心接口为:

alipay.trade.wap.pay

接入时应查阅支付宝开放平台的“手机网站支付”文档,不要误用 App 支付、电脑网站支付或当面付文档。

测试环境和 HTTPS 需要注意以下几点:

  • 联调可以使用支付宝开放平台的沙箱环境。沙箱会提供单独的应用参数和测试账号。
  • 本地 PHP 环境可以测试下单、签名和拉起支付宝收银台。
  • 支付宝服务器无法访问 localhost 或局域网地址,所以异步通知地址 notify_url 必须能通过公网访问。
  • 本地开发生成支付请求时,HTTPS 通常不是绝对前提。生产环境应使用有效的 HTTPS 地址,具体要求以支付宝开放平台当前的产品规则和安全要求为准。
  • 同步跳转地址 return_url 只能用于展示支付结果。最终支付状态必须通过异步通知或主动查询确认。

应该选择哪份文档

如果要在 H5 页面中通过浏览器唤起支付宝付款,应使用“手机网站支付”产品,对应接口为:

alipay.trade.wap.pay

下面是几种容易混淆的支付产品:

使用场景对应产品或接口
手机浏览器中的 H5 页面手机网站支付:alipay.trade.wap.pay
PC 浏览器网页电脑网站支付:alipay.trade.page.pay
原生 Android、iOS AppApp 支付:alipay.trade.app.pay
扫码支付、付款码支付当面付相关接口

如果业务页面运行在微信、钉钉或其他应用的内置浏览器中,还要确认该浏览器是否允许直接唤起支付宝。部分内置浏览器会限制跳转,这类限制无法通过 PHP 接口解决,通常需要提示用户改用系统浏览器打开页面。

接入前需要准备的参数

正式环境通常需要以下参数:

  • 支付宝开放平台应用的 app_id
  • 商户应用私钥
  • 支付宝公钥
  • 签名算法,一般使用 RSA2
  • 支付完成后的同步跳转地址 return_url
  • 支付宝异步通知地址 notify_url

沙箱环境必须使用沙箱控制台提供的参数,不能混用正式环境的应用编号、密钥或账号。

常用网关如下:

沙箱:https://openapi.alipaydev.com/gateway.do
正式:https://openapi.alipay.com/gateway.do

支付宝开放平台的界面和沙箱入口可能发生调整,实际参数应以当前控制台显示的内容为准。

PHP 发起 H5 支付

下面的示例使用支付宝 PHP SDK 中常见的 AopClient 和 AlipayTradeWapPayRequest 类。不同版本 SDK 的目录结构和加载方式可能不同,类名、命名空间和自动加载配置请以实际下载的 SDK 为准。

<?php

require_once __DIR__ . '/vendor/autoload.php';

$aop = new AopClient();

// 沙箱环境;上线时改为正式网关
$aop->gatewayUrl = 'https://openapi.alipaydev.com/gateway.do';

$aop->appId = '你的沙箱APP_ID';
$aop->rsaPrivateKey = '你的应用私钥';
$aop->alipayrsaPublicKey = '你的支付宝公钥';

$aop->apiVersion = '1.0';
$aop->signType = 'RSA2';
$aop->postCharset = 'UTF-8';
$aop->format = 'json';

$request = new AlipayTradeWapPayRequest();

$outTradeNo = 'ORDER_' . date('YmdHis') . random_int(1000, 9999);

$bizContent = [
    'out_trade_no' => $outTradeNo,
    'total_amount' => '0.01',
    'subject' => 'H5支付测试订单',
    'product_code' => 'QUICK_WAP_WAY',
    'quit_url' => 'https://example.com/order/cancel',
];

$request->setBizContent(
    json_encode($bizContent, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
);

$request->setReturnUrl('https://example.com/payment/alipay/return');
$request->setNotifyUrl('https://example.com/payment/alipay/notify');

// SDK通常返回一段自动提交到支付宝网关的HTML表单
$html = $aop->pageExecute($request, 'POST');

header('Content-Type: text/html; charset=UTF-8');
echo $html;

各参数的作用如下:

  • out_trade_no 是商户订单号,在商户系统内必须唯一。
  • total_amount 建议使用字符串传递,以免出现浮点数精度问题。
  • subject 是订单标题。
  • product_code 在手机网站支付中通常填写 QUICK_WAP_WAY。
  • quit_url 是用户中途退出支付时返回的地址。
  • notify_url 用于接收服务器异步通知。
  • return_url 是支付后浏览器跳转的地址。

不要直接拼接未经签名的支付宝网关 URL。请求参数必须按支付宝的规则签名。使用官方 SDK 可以减少签名、编码和参数排序方面的错误。

处理异步通知

确认支付结果主要依靠异步通知。通知接口收到请求后,应先验签,再核对订单号、金额、商户身份和交易状态。

<?php

require_once __DIR__ . '/vendor/autoload.php';

$aop = new AopClient();
$aop->alipayrsaPublicKey = '你的支付宝公钥';

$params = $_POST;

$isValid = $aop->rsaCheckV1(
    $params,
    $aop->alipayrsaPublicKey,
    'RSA2'
);

if (!$isValid) {
    http_response_code(400);
    echo 'failure';
    exit;
}

$outTradeNo = $params['out_trade_no'] ?? '';
$tradeNo = $params['trade_no'] ?? '';
$tradeStatus = $params['trade_status'] ?? '';
$totalAmount = $params['total_amount'] ?? '';
$appId = $params['app_id'] ?? '';

// 从数据库读取订单,核对以下信息:
// 1. out_trade_no 是否存在
// 2. total_amount 是否与订单金额一致
// 3. app_id、seller_id 等商户信息是否匹配
// 4. 订单是否已经处理过,避免重复入账

if ($tradeStatus === 'TRADE_SUCCESS' || $tradeStatus === 'TRADE_FINISHED') {
    // 使用事务或幂等逻辑更新订单状态
    // 保存支付宝交易号 $tradeNo

    echo 'success';
    exit;
}

echo 'failure';

支付宝可能重复发送异步通知,所以订单更新逻辑必须具备幂等性。已支付订单再次收到相同通知时,不能重复增加余额、发货或发放权益。

处理成功后,应按接口要求输出:

success

如果接口返回其他内容、处理超时或无法访问,支付宝可能继续重试通知。

本地环境如何测试

本地测试可以分为支付请求生成和异步通知联调两部分。

本地完成支付请求生成

PHP 服务即使运行在下面的本地地址,也可以生成支付表单:

http://localhost:8000

用户点击支付后,浏览器会把请求提交到支付宝沙箱网关。因此,本地环境可以测试以下内容:

  • 参数组装
  • RSA2 签名
  • 支付页面跳转
  • 沙箱账号登录
  • 沙箱支付流程
  • 同步返回页面

例如,可以使用 PHP 内置服务器启动项目:

php -S 127.0.0.1:8000 -t public

让支付宝访问异步通知接口

支付宝服务器无法访问以下地址:

http://localhost:8000/payment/alipay/notify
http://127.0.0.1:8000/payment/alipay/notify
http://192.168.1.10/payment/alipay/notify

测试异步通知时,需要提供公网可访问的地址。常见处理方式有:

  • 把测试代码部署到公网测试服务器。
  • 使用带有 HTTPS 域名的开发或预发布环境。
  • 使用内网穿透服务,把临时公网地址转发到本地端口。

获得公网地址后,可以把通知地址设置为:

https://test.example.com/payment/alipay/notify

使用临时穿透地址时,要确保地址在整个支付和通知期间保持有效,同时检查穿透服务是否会修改 POST 请求体或参数编码。

是否必须使用 HTTPS

不同环节的要求并不完全相同:

  • 本地页面生成支付请求:开发调试时通常可以使用 HTTP。
  • 跳转支付宝收银台:支付宝网关本身使用 HTTPS。
  • return_url 和 notify_url:生产环境应配置 HTTPS。
  • 是否强制使用 HTTPS:可能受到产品规则、应用配置、浏览器策略和开放平台当前审核要求的影响,应以接入时的官方文档和控制台校验结果为准。

即使测试环境暂时接受 HTTP,正式上线时也不建议继续使用。HTTPS 可以防止支付结果、订单编号等数据在传输过程中被窃听或篡改。

测试流程

可以按下面的顺序进行联调:

  1. 在支付宝开放平台创建应用,确认已开通手机网站支付能力。
  2. 进入沙箱环境,获取沙箱 app_id、测试账号和相关配置。
  3. 生成应用 RSA2 密钥,并正确配置支付宝公钥。
  4. 把 SDK 网关设置为沙箱网关。
  5. 创建金额较小、订单号唯一的测试订单。
  6. 在手机浏览器或浏览器的移动设备模式中打开支付页面。
  7. 使用沙箱买家账号完成支付。
  8. 检查同步跳转页面。
  9. 通过公网通知地址检查异步通知、验签和订单更新。
  10. 必要时调用交易查询接口,核实最终交易状态。
  11. 上线前替换正式环境的网关、app_id、密钥和账号,然后再次完成整套联调。

常见问题

页面提示签名错误

一般需要检查以下内容:

  • 应用私钥是否属于当前 app_id
  • 配置的是“支付宝公钥”,还是误用了“应用公钥”
  • 是否混用了沙箱和正式环境的密钥
  • sign_type 是否为 RSA2
  • 字符集是否统一为 UTF-8
  • 私钥是否因换行、空格或格式转换而损坏
  • 请求参数是否在签名后被修改

浏览器跳转成功,但订单没有变成已支付

应重点检查异步通知接口:

  • notify_url 是否能通过公网访问
  • 接口是否允许支付宝发送的 POST 请求
  • Web 服务器或防火墙是否拦截了请求
  • 验签时是否使用了正确的支付宝公钥
  • 接口处理成功后是否输出纯文本 success
  • 数据库更新是否发生异常或被回滚

如果暂时没有收到异步通知,不要只根据 return_url 判断支付成功。此时可以调用支付宝交易查询接口进行补偿查询。

同步返回显示支付成功,能否直接发货

不能。return_url 只是浏览器跳转地址,用户可以刷新、重复访问或伪造该地址。业务系统必须先验签并核对交易金额、订单号和商户信息,再根据异步通知或主动查询结果更新订单。

沙箱测试完成后只修改网关即可上线吗

不够。切换到正式环境时,至少要重新确认以下配置:

  • 正式应用的 app_id
  • 正式应用私钥
  • 正式支付宝公钥
  • 正式网关地址
  • 产品签约或应用能力状态
  • 正式回调域名
  • 订单金额与商户信息校验
  • 服务器时间、网络和日志配置

沙箱参数和正式参数必须分开保存,避免配置混用造成签名失败,或者把订单请求发送到错误的环境。

备注:内容仅供参考。