app内嵌支付宝SDK支付时如何配置通知接口服务器IP
结论
支付宝 App 支付的异步通知无需在客户端 SDK 中配置服务器 IP。商户服务端创建支付订单时,需要设置 notify_url,并填写支付宝可通过公网访问的 HTTP/HTTPS 地址,例如:
https://pay.example.com/alipay/notify
建议使用 HTTPS 域名。不要填写 localhost、127.0.0.1、局域网 IP 或 App 用户的 IP,也不要误把支付宝网关地址填成通知地址。
如果支付宝开放平台的某项配置明确要求填写“服务器 IP 白名单”,一般应填写商户服务端调用支付宝接口时使用的固定公网出口 IP。服务器 IP 白名单与接收支付通知的 notify_url 是两项不同的配置。
为什么不能配置 App 或内网 IP
App 支付完成后,支付宝服务器会直接向商户后台发送异步通知。调用链路如下:
支付宝服务器 → 商户 notify_url → 商户业务系统
通知过程不经过用户手机。手机可能连接移动网络或家庭 Wi-Fi,也可能处于 NAT 环境,IP 经常变化,无法稳定接收公网请求。因此,不能把 App 所在设备的 IP 作为通知服务器地址。
以下地址通常不能用于正式环境:
http://localhost/alipay/notify
http://127.0.0.1/alipay/notify
http://192.168.1.10/alipay/notify
即使服务部署在云服务器上,也要确认域名解析到了正确的公网入口,并确保反向代理、负载均衡和防火墙允许外部访问该接口。
正确配置步骤
1. 准备公网通知接口
商户服务端需要提供一个无需用户登录,并且能够接收支付宝 POST 请求的接口:
POST https://pay.example.com/alipay/notify
该接口需要满足以下条件:
- 支付宝服务器可以通过公网访问;
- 建议使用 HTTPS;
- 不依赖 Cookie、登录状态或 App 会话;
- 不返回 HTML 页面或跳转地址;
- 可以处理重复通知;
- 处理成功后返回纯文本
success。
2. 创建订单时设置 notify_url
notify_url 应由服务端设置,不能由 App 客户端自由传入。以下是 Java SDK 的常见调用方式:
AlipayClient alipayClient = new DefaultAlipayClient(
"https://openapi.alipay.com/gateway.do",
appId,
merchantPrivateKey,
"json",
"UTF-8",
alipayPublicKey,
"RSA2"
);
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
request.setNotifyUrl("https://pay.example.com/alipay/notify");
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setOutTradeNo(outTradeNo);
model.setSubject("订单支付");
model.setTotalAmount("99.00");
model.setProductCode("QUICK_MSECURITY_PAY");
request.setBizModel(model);
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
String orderString = response.getBody();
服务端将 orderString 返回给 App,App 再调用支付宝 SDK 发起支付。商户私钥、支付宝公钥等敏感配置必须保存在服务端,不能打包到 App 中。
不同版本 SDK 的类名和初始化方式可能不同,应以项目实际使用的支付宝服务端 SDK 为准,但 notify_url 的用途不会改变。
3. 接收并验证异步通知
收到通知后,不能只根据请求中的 trade_status 更新订单,必须先完成验签。Java 示例:
@PostMapping(
value = "/alipay/notify",
produces = "text/plain;charset=UTF-8"
)
@ResponseBody
public String receiveNotify(HttpServletRequest request) {
Map<String, String> params = new HashMap<>();
request.getParameterMap().forEach((name, values) -> {
if (values != null && values.length > 0) {
params.put(name, String.join(",", values));
}
});
try {
boolean verified = AlipaySignature.rsaCheckV1(
params,
alipayPublicKey,
"UTF-8",
"RSA2"
);
if (!verified) {
return "failure";
}
String appId = params.get("app_id");
String outTradeNo = params.get("out_trade_no");
String tradeNo = params.get("trade_no");
String tradeStatus = params.get("trade_status");
String totalAmount = params.get("total_amount");
// 还需要校验 app_id、订单号、订单金额以及卖家身份等业务字段。
// 更新订单时必须做幂等处理,避免重复记账。
if ("TRADE_SUCCESS".equals(tradeStatus)
|| "TRADE_FINISHED".equals(tradeStatus)) {
paymentService.confirmPayment(
outTradeNo,
tradeNo,
totalAmount
);
}
return "success";
} catch (Exception e) {
return "failure";
}
}
这个示例只展示核心流程。生产环境还需要记录必要的通知信息和异常日志,但不能输出私钥、完整签名或其他敏感数据。
“服务器 IP 白名单”应该填什么
如果支付宝开放平台或相关产品配置中明确提供了服务器 IP 白名单,应填写商户后台调用支付宝开放接口时使用的公网出口 IP,例如 NAT 网关、负载均衡出口或固定公网地址。
不要填写:
- App 用户手机的 IP;
- 后端服务器的
127.0.0.1; 10.x.x.x、172.16.x.x、192.168.x.x等内网 IP;- 域名解析前使用的临时测试 IP;
- 未经确认的支付宝服务器 IP。
如果后端有多台机器或多个出口,需要配置所有实际使用的公网出口 IP。动态公网 IP 发生变化后,白名单可能失效,因此生产环境通常需要固定出口 IP。
IP 白名单主要用于限制商户服务端对支付宝接口的调用,不能代替异步通知验签。支付宝通知的来源地址可能随网络架构调整而变化,不建议自行维护来源 IP 列表,并将其作为唯一的安全依据。是否需要配置特定的入站白名单,应以支付宝开放平台对应产品当前的官方要求为准。
上线前检查
上线前至少需要确认:
notify_url可以从公网直接访问;- 域名 DNS 解析正确;
- HTTPS 证书有效,证书链完整;
- 防火墙、WAF、网关和反向代理允许 POST 请求;
- 接口不会被登录认证、CSRF 校验或验证码拦截;
- 通知参数已使用支付宝公钥验签;
app_id、订单号、金额、收款方等信息与本地订单一致;- 更新订单时做了幂等处理;
- 处理成功后返回纯文本
success; - App 前台支付结果只用于页面展示,最终支付状态以服务端异步通知或主动查询结果为准。
实际配置的重点不是给 App SDK 填写服务器 IP,而是在服务端创建订单时设置稳定、可通过公网访问的 notify_url。只有平台明确要求配置 IP 白名单时,才需要填写商户服务端的固定公网出口 IP。
备注:内容仅供参考。
