PAYATHON 2026

app支付沙箱环境提示系统繁忙(ALIN10146)如何解决?

支付老李

结论

ALIN10146 通常是支付宝客户端显示的通用失败提示,仅凭这个错误码无法确定具体原因。在沙箱 App 支付中,常见原因包括:

  • app_id、网关、应用私钥和支付宝公钥并非来自同一套沙箱配置;
  • 服务端生成的订单字符串缺少参数,或客户端对订单字符串进行了再次编码、拼接或修改;
  • 签名方式、字符集或密钥格式配置有误;
  • 混用了正式环境的买家账号、应用配置或网关;
  • 沙箱环境暂时异常。

建议先查看支付宝开放平台的沙箱日志,以及服务端调用 alipay.trade.app.pay 时返回的原始响应。服务器端的异步通知验签发生在支付之后,通常不会直接导致客户端弹出 ALIN10146。

优先检查环境配置

沙箱支付使用的所有配置都必须来自同一个沙箱应用,不能与正式环境参数混用:

网关:https://openapi.alipaydev.com/gateway.do
app_id:沙箱应用 APPID
应用私钥:与沙箱应用公钥匹配的私钥
支付宝公钥:沙箱应用页面提供的支付宝公钥
sign_type:RSA2
charset:UTF-8

这里需要分清两个概念:

  • 应用私钥:用于给商户请求签名。
  • 支付宝公钥:用于验证支付宝通知或响应的签名。

支付宝公钥不是应用公钥,也不能从应用私钥中直接复制。密钥使用错误时,即使其他参数看起来正常,请求也可能无法通过校验。

如果采用证书模式,应用证书、支付宝公钥证书和支付宝根证书必须配套使用,不能和普通公钥模式混在一起。

正确生成 App 支付订单字符串

订单参数和签名应由服务端生成。客户端只需把服务端返回的完整订单字符串交给支付宝 SDK,不要自行重新签名。

下面是 Java 服务端使用普通公钥模式生成订单字符串的示例:

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;

public class AlipayOrderService {

    private static final String GATEWAY =
            "https://openapi.alipaydev.com/gateway.do";
    private static final String APP_ID =
            "你的沙箱APPID";
    private static final String APP_PRIVATE_KEY =
            "你的应用私钥";
    private static final String ALIPAY_PUBLIC_KEY =
            "沙箱环境的支付宝公钥";

    public String createOrder() throws AlipayApiException {
        AlipayClient alipayClient = new DefaultAlipayClient(
                GATEWAY,
                APP_ID,
                APP_PRIVATE_KEY,
                "json",
                "UTF-8",
                ALIPAY_PUBLIC_KEY,
                "RSA2"
        );

        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        model.setSubject("测试商品");
        model.setOutTradeNo(createUniqueTradeNo());
        model.setTotalAmount("0.01");
        model.setProductCode("QUICK_MSECURITY_PAY");

        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
        request.setBizModel(model);
        request.setNotifyUrl("https://example.com/alipay/notify");

        AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);

        if (!response.isSuccess()) {
            throw new IllegalStateException(
                    "生成支付订单失败,code=" + response.getCode()
                            + ", subCode=" + response.getSubCode()
                            + ", msg=" + response.getMsg()
                            + ", subMsg=" + response.getSubMsg()
            );
        }

        return response.getBody();
    }

    private String createUniqueTradeNo() {
        return "TEST" + System.currentTimeMillis();
    }
}

服务端必须把 response.getBody() 原样返回给客户端,不要进行 URL 解码、拆分重组或二次签名。

Android 客户端调用示例:

final String orderInfo = orderStringFromServer;

Runnable payRunnable = () -> {
    PayTask payTask = new PayTask(activity);
    Map<String, String> result = payTask.payV2(orderInfo, true);

    String resultStatus = result.get("resultStatus");
    String memo = result.get("memo");
    String rawResult = result.get("result");

    Log.d("Alipay", "resultStatus=" + resultStatus);
    Log.d("Alipay", "memo=" + memo);
    Log.d("Alipay", "result=" + rawResult);
};

Thread payThread = new Thread(payRunnable);
payThread.start();

除了弹窗里的 ALIN10146,还要完整记录 payV2() 返回的 resultStatus、memo 和 result。生产日志中不宜长期保留完整订单字符串、签名或用户隐私数据。

按顺序排查

1. 检查服务端原始响应

SDK 调用失败后,不要继续向客户端返回空字符串或异常内容。至少应记录:

response.getCode();
response.getSubCode();
response.getMsg();
response.getSubMsg();
response.getBody();

真正有助于定位问题的通常是 subCode 和 subMsg,而不是客户端显示的通用提示。

2. 核对必要业务参数

App 支付通常至少需要正确设置以下参数:

subject
out_trade_no
total_amount
product_code=QUICK_MSECURITY_PAY

需要注意:

  • out_trade_no 必须在商户系统内保持唯一。重复测试时,不要一直使用同一个订单号。
  • total_amount 应是合法的十进制金额字符串,例如 "0.01"。
  • subject 不能为空。
  • product_code 应设置为 QUICK_MSECURITY_PAY。

不要手工拼接 JSON 后随意进行 URL 编码。应优先使用支付宝服务端 SDK 构造请求。

3. 检查订单字符串是否被修改

可以分别记录以下信息:

  1. 服务端 response.getBody() 的长度和摘要;
  2. 客户端收到字符串后的长度和摘要;
  3. 调用 payV2() 前字符串的长度和摘要。

如果订单字符串经过 JSON、表单或数据库传递,要确认 &、+、%、引号和换行没有被转义或替换。常见错误包括:

把完整订单字符串再次 URLEncoder.encode()
把字符串按 & 拆开后重新排序
将 + 解析为空格
复制时引入换行
对 sign 字段进行二次编码

4. 检查密钥格式

配置文件中的私钥通常应保存为连续的 Base64 内容。是否保留 PEM 头尾,取决于当前 SDK 和密钥加载方式。检查时尤其要注意:

  • 是否误用了应用公钥;
  • 是否使用了其他应用的私钥;
  • 是否混入空格、换行或不可见字符;
  • 密钥类型是否符合当前 SDK 的要求;
  • 配置的 RSA2 是否与实际签名方式一致。

不要为了所谓的兼容性同时尝试多套密钥。应先在沙箱后台确认当前应用公钥,再核对本地与之对应的私钥。

5. 使用沙箱买家账号

沙箱交易应使用开放平台沙箱页面提供的买家账号进行测试。普通的正式支付宝账号不一定能完成沙箱交易。

还需确认:

  • 支付宝客户端可以正常拉起;
  • 沙箱账号状态正常;
  • 当前测试配置属于对应的沙箱应用;
  • 手机系统时间准确;
  • 网络未受到代理、抓包证书或安全软件的干扰。

6. 检查 SDK 集成

如果服务端生成的订单没有问题,但客户端仍然失败,可以继续检查:

  • 支付宝 App 支付 SDK 是否完整集成;
  • 项目中是否同时存在多个不同版本的支付宝 SDK;
  • 混淆规则是否有遗漏;
  • Android Activity 和线程调用方式是否符合 SDK 接入要求;
  • iOS 的 URL Scheme 和回调是否配置正确;
  • 客户端是否误用 Demo 中的固定订单或旧订单替换了测试订单。

不要长期使用 SDK Demo 中的示例密钥、固定订单号或本地签名代码。Demo 只用于说明调用流程,实际应用应由服务端统一生成订单和签名。

验签应如何处理

异步通知验签使用支付宝公钥,而不是应用公钥:

boolean verified = AlipaySignature.rsaCheckV1(
        request.getParameterMap(),
        ALIPAY_PUBLIC_KEY,
        "UTF-8",
        "RSA2"
);

验签通过后,还需要核对:

app_id
out_trade_no
total_amount
seller_id(如果业务中有保存和校验)
trade_status

不能把客户端返回的支付成功直接作为最终入账依据。最终结果应以服务端查询结果,或验签通过的支付宝异步通知为准。

异步通知验签发生在支付请求被受理之后。如果付款页面还没有正常打开就出现 ALIN10146,应先检查环境配置、订单参数和请求签名,不必把排查重点放在通知验签代码上。

如何判断是否为沙箱临时异常

只有同时满足以下条件,才更有可能是沙箱服务暂时异常:

  • 服务端可以成功生成完整的订单字符串;
  • 沙箱 APPID、网关和密钥已经确认一致;
  • 测试时使用了沙箱买家账号;
  • 使用同一组订单参数重新生成新订单号后,仍然支付失败;
  • SDK 返回内容中没有更具体的业务错误;
  • 开放平台请求日志中没有参数或签名错误。

这时可以等待一段时间,使用新的 out_trade_no 再次测试,并查看支付宝开放平台的接口调用日志或服务状态。如果仍无法定位,可向支付宝技术支持提供请求时间、沙箱 APPID、接口名称、订单号和平台返回的错误信息,但不要提交应用私钥。

大多数 ALIN10146 问题都可以通过服务端原始响应或开放平台调用日志找到原因。先确认请求是否正确生成并被支付宝受理,再检查客户端和异步通知,可以避免把通用错误提示误判为验签问题。

备注:内容仅供参考。