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

Quarkus项目使用OkHttp3 Client遇Connection reset问题求助

问题解答:Quarkus中OkHttp3 Client的Connection Reset异常

问题概述

生产环境调用下游API时偶尔抛出如下异常:

java.net.SocketException: Connection reset at java.net.SocketInputStream.read(SocketInputStream.java:186) ~[?:?] at java.net.SocketInputStream.read(SocketInputStream.java:140)

项目作为中间层转发请求:GET请求重试两次仍失败,第三次成功;POST请求因幂等性限制无法重试,首次即失败。

当前核心代码:

public class CustomOkHttpClient extends HttpClient {
    private OkHttpClient client;

    public Response callDownstream(HttpRequest clientRequest) {
        Response clientResponse = null;
        try {
            Call call = client.newCall(clientRequest);
            clientResponse = call.execute();
            return parseClientResponse(clientResponse, responseClass);
        } catch (final Exception exception) {
            logger.error("Exception occurred");
            throw exception;
        } finally {
            if (null!=clientResponse) {
                clientResponse.close();
            }
        }
    }
}

依赖版本:

  • okhttp-urlconnection: 5.0.0-alpha.2
  • logging-interceptor: 4.9.3
  • mockwebserver: 4.9.0

已尝试方案:

  • 在finally块中关闭响应连接
  • 增加readTimeout,但问题未解决

疑问解答

2. 是否因连接长时间闲置被关闭,导致后续请求失败?

是的,这是该异常最常见的诱因。OkHttp默认通过连接池复用TCP连接,若连接被下游服务器或中间网络设备(负载均衡、防火墙)因闲置超时关闭,OkHttp尝试复用失效连接时就会抛出Connection Reset异常。

GET请求第三次成功,正是因为前两次复用了失效连接,第三次OkHttp会移除失效连接并创建新连接;POST请求未重试,直接使用失效连接导致失败。

另外,你的OkHttp依赖存在跨版本不兼容问题:预览版5.0.0-alpha.2与4.x版本的logging-interceptor、mockwebserver混用,可能导致连接池管理逻辑异常,加重此类问题。

1. 后续可采取的解决方法

(1)统一并升级OkHttp到稳定版

弃用预览版5.0.0-alpha.2,将所有OkHttp相关依赖统一升级到最新稳定版(如4.12.0),避免版本冲突:

<!-- Maven示例 -->
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.12.0</version>
</dependency>
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>logging-interceptor</artifactId>
    <version>4.12.0</version>
</dependency>
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>mockwebserver</artifactId>
    <version>4.12.0</version>
</dependency>

(2)调整连接池闲置超时,匹配下游配置

将OkHttp连接池的keepAliveDuration设置为小于下游服务器/网络设备的闲置超时时间(比如下游设300秒,你设250秒),避免复用已被关闭的连接:

OkHttpClient client = new OkHttpClient.Builder()
       .connectionPool(new ConnectionPool(5, 250, TimeUnit.SECONDS))
       .build();

(3)添加连接有效性校验拦截器

自定义拦截器,在请求发送前校验连接是否存活,若失效则强制创建新连接:

public class ConnectionValidityInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        Connection connection = chain.connection();
        if (connection!= null &&!connection.isAlive()) {
            connection.socket().close();
            // 重置超时参数,强制创建新连接
            return chain.withConnectTimeout(0, TimeUnit.MILLISECONDS)
                   .withReadTimeout(0, TimeUnit.MILLISECONDS)
                   .withWriteTimeout(0, TimeUnit.MILLISECONDS)
                   .proceed(request);
        }
        return chain.proceed(request);
    }
}

添加到客户端构建器:

OkHttpClient client = new OkHttpClient.Builder()
       .addInterceptor(new ConnectionValidityInterceptor())
       .build();

(4)针对非幂等请求添加定向重试(需谨慎)

若下游POST API支持幂等(比如通过请求ID去重),可针对Connection Reset这类网络异常添加重试逻辑:

public Response callDownstream(HttpRequest clientRequest) {
    int retryCount = 0;
    final int maxRetries = 2;
    while (retryCount <= maxRetries) {
        Response clientResponse = null;
        try {
            Call call = client.newCall(clientRequest);
            clientResponse = call.execute();
            return parseClientResponse(clientResponse, responseClass);
        } catch (SocketException e) {
            if (retryCount == maxRetries) {
                logger.error("Max retries reached for request", e);
                throw e;
            }
            retryCount++;
            logger.warn("Connection reset, retrying request (attempt " + retryCount + ")");
        } catch (final Exception exception) {
            logger.error("Exception occurred", exception);
            throw exception;
        } finally {
            if (null!= clientResponse) {
                clientResponse.close();
            }
        }
    }
    throw new IllegalStateException("Unexpected retry loop exit");
}

注意:必须确认下游API支持重复调用,否则会导致数据重复提交。

(5)启用详细日志定位问题

通过logging-interceptor开启连接相关日志,生产环境可调整为Level.HEADERS避免日志过大:

HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);

OkHttpClient client = new OkHttpClient.Builder()
       .addInterceptor(loggingInterceptor)
       .build();

通过日志可确认是否是连接复用导致的异常。


内容的提问来源于stack exchange,提问作者Dinesh Verma

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 07:23:20