You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring启动后调用PIX SDK API抛出SocketException异常排查

问题描述

我调用一个用于列出PIX二维码的SDK API时遇到如下错误:

java.net.SocketException: Unexpected end of file from server
at java.base/sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:955)
at java.base/sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:759)
at java.base/sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:952)
at java.base/sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:759)
at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1690)
at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1599)
at java.base/java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:531)
at java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:307)

我的调用代码如下:

public static void main(String[] args) {
    SpringApplication.run(App.class, args);
    callApi();
}

private static void callApi() {
    try {
        final JSONObject credentials = new JSONObject();
        credentials.put("client_id", "client_id");
        credentials.put("client_secret", "client_secret");
        credentials.put("certificate", "certificate.p12");
        credentials.put("sandbox", "false");
        credentials.put("debug", "false");
        SDKPay sdkPay = new SDKPay(credentials);
        JSONObject response = sdkPay.call("listPix", new HashMap<>(), new JSONObject());
        System.out.print("PIX response: " + response);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

关键现象:

  • Spring启动前调用callApi()可以正常运行
  • Spring启动前调用过callApi(),之后再调用也正常
  • 仅在Spring启动后首次调用时出现上述错误

验证代码:

public static void main(String[] args) {
    callApi(); // Spring启动前调用可正常运行
    SpringApplication.run(App.class, args);
    callApi(); // 启动前调用过之后再调用也正常
}

private static void callApi() {
    try {
        final JSONObject credentials = new JSONObject();
        credentials.put("client_id", "client_id");
        credentials.put("client_secret", "client_secret");
        credentials.put("certificate", "certificate.p12");
        credentials.put("sandbox", "false");
        credentials.put("debug", "false");
        SDKPay sdkPay = new SDKPay(credentials);
        JSONObject response = sdkPay.call("listPix", new HashMap<>(), new JSONObject());
        System.out.print("PIX response: " + response);
    } catch (Exception e) {
        e.printStackTrace();
    }
}
可能的原因及解决思路

1. Spring启动修改了全局SSL/HTTP客户端配置

Spring启动时会初始化自身的HTTP客户端(如RestTemplate、WebClient),或修改JVM默认的SSL上下文。如果SDK依赖JVM全局配置,Spring启动后的首次调用会因为全局配置未完全初始化或被修改导致不兼容;而提前调用SDK时,SDK会先初始化自己的SSL配置,后续Spring的修改不会影响已初始化的连接。

解决办法:

  • 改用Spring生命周期钩子初始化SDK:将SDK的初始化和调用放在@PostConstruct方法中,确保Spring完成所有上下文初始化后再执行:
@SpringBootApplication
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }

    @PostConstruct
    public void initAndCallApi() {
        callApi();
    }

    private void callApi() {
        // 原callApi逻辑
    }
}
  • 查看SDK文档,是否支持传入自定义SSLContext或HttpClient实例,避免依赖JVM全局配置。

2. HTTP连接池未预热

SDK内部可能使用了HTTP连接池,Spring启动过程中占用网络资源或修改连接参数,导致首次请求时连接池无法建立有效连接;提前调用SDK时已预热连接池,后续请求可复用已有连接。

解决办法:

  • 在Spring启动完成后先发起一次轻量SDK调用(如测试接口)预热连接池,再执行实际的listPix调用;
  • 检查SDK配置,调整连接超时、最大连接数等参数适配Spring环境。

3. 证书加载路径冲突

SDK使用的p12证书路径,在Spring启动后被Spring的资源加载机制修改了解析逻辑,导致首次加载失败;提前调用时用的是JVM默认路径解析,能正常找到证书。

解决办法:

  • 使用绝对路径指定证书文件,避免相对路径解析问题:
credentials.put("certificate", "/usr/app/certificate.p12");
  • 将证书放在Spring的resources目录下,通过Spring Resource接口获取输入流后传递给SDK(若SDK支持)。

内容的提问来源于stack exchange,提问作者Darlan Candiotto

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 21:57:29