新建购物网站如何绑定支付宝支付?
结论
购物网站接入支付宝,并不是填入一个支付宝账号就能完成。整个接入过程包括:
- 使用企业或个体工商户主体开通支付宝商家账号。
- 创建网页应用,申请相应的支付产品。
- 配置应用私钥、支付宝公钥或应用证书。
- 由网站服务端调用支付宝支付接口。
- 接收并验证支付宝发送的异步通知。
- 查询订单结果并更新支付状态。
PC 网站通常使用 alipay.trade.page.pay,手机浏览器中的 H5 商城通常使用 alipay.trade.wap.pay。如果网站同时支持电脑和手机,应根据访问终端分别调用对应的接口。
一、准备接入条件
正式接入前,通常需要准备:
- 支付宝商家账号;
- 已完成实名认证的企业或个体工商户主体;
- 已上线或能够正常访问的购物网站;
- 网站域名及相关经营资质;
- 服务端开发环境;
- 可用于同步跳转和异步通知的 HTTPS 地址;
- 与实际经营内容一致的商品、服务和页面信息。
商户主体、经营类目以及支付宝平台当时的审核规则,会影响可申请的支付产品。后台菜单名称也可能发生变化,具体以支付宝开放平台的实际页面为准。
二、创建支付宝应用
登录支付宝开放平台,在控制台中创建网页或移动应用。应用审核通过后,平台会分配一个 app_id,也就是网站在支付宝侧的应用编号。
接下来需要为应用申请支付能力:
- PC 商城申请电脑网站支付;
- 手机 H5 商城申请手机网站支付;
- 如果需要退款、订单查询等功能,还要确认应用已取得相应的接口权限。
创建应用和签约支付产品是两个独立环节。取得 app_id 并不代表可以立即收款。如果支付产品尚未签约或未通过审核,正式环境中的支付仍然无法使用。
三、配置签名密钥
支付宝接口通常使用 RSA 签名。常见的配置方式有公钥模式和证书模式,应按照开放平台提供的接入方式选择,两种模式不能混用。
以公钥模式为例,配置过程如下:
- 在安全工具或可信环境中生成 RSA2 密钥对;
- 将应用公钥上传到支付宝开放平台;
- 保存平台返回的支付宝公钥;
- 将应用私钥安全地配置在购物网站服务端。
以下几个名称容易混淆:
应用私钥:由网站保存,用于为请求签名;应用公钥:上传给支付宝,供支付宝验证网站的签名;支付宝公钥:由支付宝提供,网站用它验证支付通知;app_id:支付宝应用编号,不是商户登录账号。
不要把应用私钥放进 JavaScript、HTML、App 安装包或公开代码仓库,也不应直接写死在源码中。生产环境可以通过密钥管理服务、加密配置或受权限控制的环境变量读取私钥。
四、确定支付流程
一次正常的网页支付流程如下:
用户提交订单
↓
网站服务端生成本地订单
↓
服务端调用支付宝支付接口
↓
浏览器跳转到支付宝收银台
↓
用户完成付款
↓
支付宝向 notify_url 发送异步通知
↓
网站验签并核对订单信息
↓
网站更新订单为已支付
return_url 是用户付款后浏览器跳转的页面。用户关闭页面或网络中断时,这个地址可能不会被访问,因此不能只凭 return_url 把订单标记为已支付。
支付结果应以验签成功的异步通知为主。如有必要,再调用订单查询接口主动核实。
五、创建本地订单
调用支付宝接口之前,网站应先创建自己的订单,至少保存以下信息:
- 商户订单号;
- 用户编号;
- 商品信息;
- 应付金额;
- 订单状态;
- 创建时间;
- 支付渠道;
- 支付宝交易号;
- 支付完成时间。
每个商户订单号都必须唯一。金额应由服务端根据商品价格、优惠规则和运费重新计算,不能直接采用浏览器提交的金额。
数据库中的金额建议使用定点小数,或者用以“分”为单位的整数保存。不要使用二进制浮点数直接计算货币金额。
六、服务端发起支付
下面以支付宝 Java SDK 和公钥模式为例,演示 PC 网站支付的基本结构。依赖版本、SDK 包名和构造方法可能随官方 SDK 调整,实际项目应参考当前所用版本的官方说明。
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.response.AlipayTradePagePayResponse;
public class AlipayPaymentService {
private static final String GATEWAY =
"https://openapi.alipay.com/gateway.do";
private final AlipayClient alipayClient;
public AlipayPaymentService(
String appId,
String appPrivateKey,
String alipayPublicKey) {
this.alipayClient = new DefaultAlipayClient(
GATEWAY,
appId,
appPrivateKey,
"json",
"UTF-8",
alipayPublicKey,
"RSA2"
);
}
public String createPagePay(
String orderNo,
String totalAmount,
String subject) throws Exception {
AlipayTradePagePayRequest request =
new AlipayTradePagePayRequest();
request.setReturnUrl(
"https://shop.example.com/payment/alipay/return"
);
request.setNotifyUrl(
"https://shop.example.com/api/payment/alipay/notify"
);
String bizContent = String.format(
"{\"out_trade_no\":\"%s\","
+ "\"product_code\":\"FAST_INSTANT_TRADE_PAY\","
+ "\"total_amount\":\"%s\","
+ "\"subject\":\"%s\"}",
escapeJson(orderNo),
escapeJson(totalAmount),
escapeJson(subject)
);
request.setBizContent(bizContent);
AlipayTradePagePayResponse response =
alipayClient.pageExecute(request);
if (!response.isSuccess()) {
throw new IllegalStateException(
"创建支付宝支付失败:" + response.getSubMsg()
);
}
return response.getBody();
}
private String escapeJson(String value) {
return value
.replace("\\", "\\\\")
.replace("\"", "\\\"");
}
}
response.getBody() 通常包含支付宝收银台的表单内容。服务端可以把它作为 HTML 返回给浏览器,再由浏览器自动提交表单并跳转。
实际开发时,建议使用 JSON 序列化库构建 biz_content,避免手工拼接 JSON。示例中的 escapeJson 仅用于说明基本思路,不能代替成熟的序列化组件。
手机网站支付的整体流程相同,但需要改用 AlipayTradeWapPayRequest,并按照手机网站支付接口的要求设置业务参数。
七、处理异步通知
异步通知是支付接入中最需要谨慎处理的部分。推荐按照以下顺序处理:
- 读取支付宝提交的全部参数;
- 使用支付宝公钥或证书验签;
- 检查
app_id是否属于当前应用; - 检查
out_trade_no是否存在; - 核对通知金额和数据库中的订单金额;
- 核对商户身份信息;
- 判断交易状态;
- 使用数据库事务更新订单;
- 返回支付宝要求的成功响应。
公钥模式下的验签示例:
import com.alipay.api.internal.util.AlipaySignature;
import java.util.Map;
public boolean verifyNotify(
Map<String, String> params,
String alipayPublicKey) throws Exception {
return AlipaySignature.rsaCheckV1(
params,
alipayPublicKey,
"UTF-8",
"RSA2"
);
}
验签通过后不能直接发货,还要核对订单号、金额、应用编号和交易状态。例如,只有确认 trade_status 属于业务允许的成功状态后,才能更新订单。
通知处理必须具备幂等性。支付宝可能针对同一笔交易重复发送通知,所以更新数据库前,应先判断订单是否已经支付,防止重复扣减库存、发放优惠券或创建发货单。
处理成功后,通知接口应按照支付宝协议返回以下纯文本:
success
如果接口超时或返回其他内容,支付宝可能继续重试通知。
八、主动查询支付结果
出现以下情况时,可以调用 alipay.trade.query 主动查询交易结果:
- 用户付款后,页面没有正常跳回;
- 异步通知出现延迟;
- 通知已经验签,但还需要进一步确认订单信息;
- 定时任务发现订单长期停留在“支付中”状态;
- 客服需要核实某笔交易。
查询时可以使用网站自己的 out_trade_no,也可以使用已经保存的支付宝 trade_no。只有当查询结果与本地订单号、金额等信息一致时,才能更新支付状态。
不要根据前端显示的“付款成功”页面直接修改订单状态,因为页面内容和请求参数都可能被伪造。
九、先在沙箱环境联调
正式上线前,应先在支付宝沙箱环境中完成联调。沙箱环境和生产环境通常使用不同的:
- 网关地址;
app_id;- 应用密钥;
- 支付宝公钥或证书;
- 测试账号。
切换到生产环境时,所有相关配置都要成套更换,不能把沙箱的 app_id 和生产环境的密钥混在一起。
至少需要测试以下场景:
- 正常付款;
- 用户取消付款;
- 重复点击支付;
- 重复收到异步通知;
- 支付成功,但同步页面没有打开;
- 通知金额与本地订单金额不一致;
- 通知验签失败;
- 已关闭订单再次支付;
- 网络超时后主动查询;
- 退款后的订单状态变化。
十、常见问题
支付页面提示“应用未签约”
常见原因包括支付产品尚未申请成功、应用还未上线,或者使用了错误的 app_id 和运行环境。
提示签名错误
可以依次检查:
- 应用私钥是否完整;
- 是否错误地使用了支付宝公钥;
- RSA2 配置是否一致;
- 密钥换行和头尾标记是否正确;
- 字符编码是否为
UTF-8; - 是否混用了公钥模式和证书模式;
- 是否混用了沙箱与生产环境的配置。
异步通知收不到
检查 notify_url 是否满足以下条件:
- 可以从公网访问;
- 使用完整的 HTTPS 地址;
- 不依赖用户登录状态;
- 没有被防火墙或网关拦截;
- 不会返回登录页面或重定向页面;
- 可以在较短时间内完成处理并响应。
通知接口不宜执行耗时过长的业务。确认支付后,可以先更新订单状态,再通过消息队列异步处理发货、积分和短信等操作。
支付成功但订单仍未支付
先检查通知日志和验签结果,然后调用订单查询接口核实交易状态。不要让客服直接手工将订单改为已支付,否则可能造成账务不一致。
十一、上线前的安全检查
正式开放支付前,应确认:
- 私钥没有出现在前端代码或代码仓库中;
- 所有支付金额都由服务端计算;
- 异步通知已经验签;
- 通知中的订单号、金额和应用信息均已核对;
- 订单更新具备事务和幂等控制;
- 支付、退款和异常通知都有日志;
- 日志中没有记录私钥、完整证书或敏感身份信息;
- 已配置订单超时关闭和支付结果补偿查询;
- 可以根据商户订单号和支付宝交易号完成对账;
- 测试环境与生产环境的配置完全隔离。
如果网站使用现成的商城系统,也可以安装该系统官方或可信服务商提供的支付宝支付插件,但商家签约、应用创建和密钥配置仍然必不可少。不要使用来源不明的“免签支付”或个人收款码轮询方案,这些方式通常存在资金、安全和合规风险。
备注:内容仅供参考。
