支付宝小游戏支付成功后如何通知指定SPI接口
结论
spi.alipay.user.gamecenter.payment.notify 是支付宝小游戏游戏币充值场景的服务提供接口(SPI)。支付成功后,支付宝游戏中心的支付系统会根据充值订单状态,主动调用开发者配置的 SPI 地址。小游戏前端不需要手动调用该接口,也不能将支付结果“转发”给它。
只有通过对应游戏币充值能力创建并完成支付的订单,才会进入这条通知链路。普通支付接口产生的异步通知不会自动转为该 SPI 通知。
通知流程
通常的处理流程如下:
- 小游戏发起游戏币充值。
- 支付宝生成并处理充值订单。
- 用户完成支付。
- 支付系统确认订单支付成功。
- 游戏中心更新充值订单状态。
- 支付宝开放平台根据应用配置,找到
spi.alipay.user.gamecenter.payment.notify对应的服务地址。 - 支付宝服务器携带订单信息和签名,请求开发者服务器。
- 开发者服务器验签、校验订单,并执行游戏币到账或状态更新。
- 开发者按照 SPI 协议返回处理结果。
- 如果请求失败、超时或响应不符合协议,支付宝可能根据该能力的重试规则再次通知。
第 6~9 步都是服务端之间的调用,不受小游戏前端页面关闭或网络中断影响。
接入步骤
1. 确认使用的是游戏币充值能力
先确认订单确实由支付宝小游戏的游戏币充值能力创建。如果使用的是普通交易、当面付或其他支付产品,应处理对应产品的异步通知,而不是等待:
spi.alipay.user.gamecenter.payment.notify
具体开通条件和订单类型,以当前支付宝开放平台控制台及对应接口文档为准。
2. 配置并发布 SPI
在应用对应的支付宝小游戏或开放平台配置中,找到游戏币充值成功状态通知服务,填写支付宝可以通过公网访问的 HTTPS 地址。
只实现接口代码还不够。如果没有在平台完成配置、发布并使其生效,支付宝就无法把 SPI 请求路由到开发者服务器。
配置时需要确认:
- SPI 是否属于当前小游戏应用;
- 应用环境是否一致,例如沙箱与正式环境;
- 服务地址是否可以从公网访问;
- HTTPS 证书是否有效;
- 应用公钥、支付宝公钥或证书配置是否匹配;
- SPI 配置是否已经提交并生效。
3. 服务端接收请求并验签
下面是一个基于支付宝网关常见表单请求形式的 Java 示例。实际请求格式、字符集和响应结构,必须以该 SPI 的当前文档为准。
@PostMapping("/alipay/gamecenter/payment/notify")
public String paymentNotify(HttpServletRequest request) throws Exception {
Map<String, String> params = new HashMap<>();
request.getParameterMap().forEach((name, values) -> {
if (values != null && values.length > 0) {
params.put(name, values[0]);
}
});
boolean verified = AlipaySignature.rsaCheckV1(
params,
alipayPublicKey,
"UTF-8",
"RSA2"
);
if (!verified) {
throw new SecurityException("Alipay signature verification failed");
}
String method = params.get("method");
if (!"spi.alipay.user.gamecenter.payment.notify".equals(method)) {
throw new IllegalArgumentException("Unexpected SPI method: " + method);
}
String bizContent = params.get("biz_content");
// 按当前 SPI 文档定义的字段反序列化 biz_content。
// 不要只依据客户端支付结果发放游戏币。
processPaymentNotification(bizContent);
// 必须替换为当前 SPI 文档要求的成功响应结构。
return buildSpiSuccessResponse();
}
如果接口使用 JSON 请求体,应读取原始请求体,并严格按照该 SPI 的签名规则验签,不能直接套用表单参数的验签代码。
4. 校验业务订单
验签成功只能说明请求来自持有对应私钥的一方,并不表示业务数据可以直接入账。服务端至少需要核对:
- 支付宝订单号和商户订单号;
- 订单是否属于当前应用;
- 订单对应的用户和游戏角色;
- 商品或游戏币档位;
- 金额、币种及订单状态;
- 订单是否已经处理;
- 通知中的状态是否满足发放条件。
不要凭经验猜测业务字段名称,应以 spi.alipay.user.gamecenter.payment.notify 当前版本的参数定义为准。
5. 做好幂等处理
支付通知可能重复到达,因此游戏币发放必须通过唯一订单号进行幂等控制,不能把“接口被调用一次”当作判断依据。
BEGIN;
SELECT status
FROM game_recharge_order
WHERE merchant_order_no = ?
FOR UPDATE;
-- 仅当订单尚未到账时执行:
-- 1. 增加游戏币
-- 2. 将充值订单更新为到账状态
-- 3. 记录支付宝订单号和通知处理时间
COMMIT;
还可以在充值记录表上建立唯一约束:
CREATE UNIQUE INDEX uk_recharge_alipay_order
ON game_recharge_record(alipay_order_no);
这样即使支付宝重复通知,或者应用因超时而重复处理,也不会再次增加游戏币。
为什么支付成功后没有收到 SPI
常见原因有:
- 实际使用的不是游戏币充值产品,因此不会触发该 SPI。
- SPI 地址尚未配置、未发布,或配置在另一个应用下。
- 沙箱订单对应了正式环境地址,或正式订单使用了沙箱配置。
- 服务地址无法从公网访问,存在 DNS、防火墙、证书或网关限制。
- 接口响应超时,或返回格式不符合 SPI 协议。
- 验签使用了错误的支付宝公钥、证书或
sign_type。 - 网关提前消费了请求体,导致业务代码无法取得完整参数。
- 代码只处理了普通支付异步通知,没有实现 SPI 方法分发。
- 支付结果仍在处理中,尚未达到游戏币充值成功状态。
- 订单已经成功,但业务处理异常,且没有保存原始通知日志。
排查时,可以使用支付宝订单号或商户订单号查询订单状态,再结合开放平台调用记录、服务器访问日志和验签日志,判断请求停在哪一层。
注意事项
不要根据小游戏前端的支付成功回调直接发放游戏币。客户端回调可能受断网、页面关闭或请求伪造影响,不能作为可靠的到账依据。最终是否到账,应由服务端通知和订单状态共同确认。
收到通知后,应先保存必要的订单标识和处理结果,再返回成功响应。耗时操作可以交给内部队列处理,但必须确保消息已经可靠落库,否则可能出现支付宝认为通知成功、业务系统却没有完成到账的情况。
SPI 的请求参数、签名方式、成功响应结构和重试规则可能因接入模式而异。接入时应以应用控制台中该 SPI 的最新协议为准,不能把普通支付接口返回 "success" 的处理方式直接套用到 spi.alipay.user.gamecenter.payment.notify。
备注:内容仅供参考。
