支付宝沙箱环境无法拉起沙箱APP并提示支付超时
结论
沙箱支付需要整套使用沙箱环境,包括沙箱网关、沙箱应用配置、沙箱版支付宝客户端和沙箱买家账号。如果服务端生成了沙箱订单,而客户端仍按正式环境调用支付 SDK,通常会拉起正式版支付宝。由于正式客户端无法识别沙箱订单,随后可能提示“支付超时”。
Android 端调用 PayTask 前,需要将支付宝 SDK 切换到沙箱环境:
EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX);
测试设备还需安装支付宝开放平台沙箱页面提供的沙箱支付宝客户端,并使用该页面分配的沙箱买家账号登录。
出现问题的原因
支付宝的正式环境与沙箱环境彼此隔离,以下内容不能跨环境混用:
- 应用
app_id - 支付宝网关
- 应用私钥和支付宝公钥
- 买家、卖家账号
- 支付订单
- 支付宝客户端环境
如果服务端请求的是沙箱网关,但 Android SDK 没有设置为 SANDBOX,SDK 仍可能尝试拉起正式版支付宝。正式客户端无法处理沙箱订单,因此可能出现支付超时、订单不存在或验签失败等问题。
正确配置步骤
1. 使用沙箱应用参数
进入支付宝开放平台的沙箱环境,获取并核对以下配置:
- 沙箱应用的
app_id - 应用私钥
- 支付宝公钥
- 沙箱网关地址
- 沙箱买家账号和登录密码
- 沙箱支付宝客户端安装包
不要混用正式应用的 app_id、密钥或账号。
沙箱网关通常配置为:
https://openapi.alipaydev.com/gateway.do
正式网关为:
https://openapi.alipay.com/gateway.do
具体地址以当前支付宝开放平台沙箱控制台显示的信息为准。
2. 服务端通过沙箱网关创建订单
以 Java SDK 为例:
AlipayClient alipayClient = new DefaultAlipayClient(
"https://openapi.alipaydev.com/gateway.do",
"沙箱APP_ID",
"应用私钥",
"json",
"UTF-8",
"沙箱支付宝公钥",
"RSA2"
);
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
request.setNotifyUrl("https://example.com/alipay/notify");
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setSubject("沙箱支付测试");
model.setOutTradeNo("TEST_" + System.currentTimeMillis());
model.setTotalAmount("0.01");
model.setProductCode("QUICK_MSECURITY_PAY");
request.setBizModel(model);
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
String orderInfo = response.getBody();
服务端应将 orderInfo 原样返回给客户端,不要让客户端重新拼接或修改其中的参数。
3. 安装并登录沙箱支付宝客户端
从支付宝开放平台的沙箱页面下载沙箱支付宝客户端,并安装到测试设备。
登录时必须使用沙箱控制台提供的买家账号和密码,不能使用真实手机号或正式支付宝账号。如果控制台当前只提供 Android 沙箱客户端,就需要使用 Android 真机测试。是否支持 iOS,以当前开放平台的说明为准。
4. 将 Android SDK 切换到沙箱环境
创建 PayTask 并调用支付接口前,先设置沙箱环境:
import com.alipay.sdk.app.EnvUtils;
import com.alipay.sdk.app.PayTask;
EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX);
Runnable payRunnable = () -> {
PayTask payTask = new PayTask(activity);
Map<String, String> result = payTask.payV2(orderInfo, true);
activity.runOnUiThread(() -> {
String resultStatus = result.get("resultStatus");
String memo = result.get("memo");
// 这里只适合展示结果,最终支付状态应由服务端确认
Log.d("AlipaySandbox", "resultStatus=" + resultStatus);
Log.d("AlipaySandbox", "memo=" + memo);
});
};
new Thread(payRunnable).start();
EnvUtils.setEnv(...) 必须在 PayTask 发起支付前执行。建议在应用初始化阶段统一设置,以免部分支付请求仍然进入正式环境。
如果当前使用的支付宝 SDK 中没有 EnvUtils,应检查 SDK 版本及对应的接入文档,不要自行假设其他参数可以替代它。
检查清单
如果仍然拉起正式版支付宝,可以按以下顺序排查:
-
Android 端是否在
PayTask.payV2()前执行了:EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX); -
手机是否已安装沙箱支付宝客户端。
-
沙箱客户端是否登录了沙箱买家账号。
-
服务端网关是否为
openapi.alipaydev.com。 -
app_id、应用私钥和支付宝公钥是否都来自同一个沙箱应用。 -
客户端收到的
orderInfo是否由沙箱配置生成,并且没有被二次编码、截断或修改。 -
out_trade_no是否唯一,订单是否已经过期或关闭。 -
修改环境配置后是否重新生成了订单。旧的正式订单和沙箱订单都不能跨环境复用。
注意事项
客户端返回的 resultStatus 只能用于界面提示,不能直接作为最终入账结果。支付是否成功,应由服务端校验异步通知的签名,或主动调用交易查询接口确认。
正式环境与沙箱环境最好采用不同的构建配置,例如:
if (BuildConfig.DEBUG) {
EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX);
}
服务端也应分别维护正式环境和沙箱环境的配置,避免应用上线后仍连接沙箱网关。切换环境时,网关、app_id、密钥、账号和客户端必须成套切换,不能只修改其中一项。
备注:内容仅供参考。
