Jetty 9.4.10 HTTP客户端偶发EOFException错误求助
解决Jetty 9.4.10.v20180503 HTTP客户端偶发EOFException问题
我来帮你分析下这个偶发的EOFException问题,从你提供的异常堆栈(虽然末尾有截断,但核心信息足够)来看,问题根源是HttpReceiverOverHTTP.earlyEOF——也就是客户端在接收服务端响应的过程中,连接被提前关闭了,导致数据流意外终止。
先把异常堆栈整理出来方便查看:
java.io.EOFException: HttpConnectionOverHTTP@571103e6(l:/192.168.1.100:27497 <-> r:api.kucoin.com/13.113.121.24:443,closed=false)=>HttpChannelOverHTTP@a423e61(exchange=HttpExchange@e7dbbf1 req=TERMINATED/null@null res=PENDING/null@null)[send=HttpSenderOverHTTP@4b7f345a(req=QUEUED,snd=COMPLETED,failure=null)[HttpGenerator@61d4e46c{s=START}],recv=HttpReceiverOverHTTP@7a7e7f01(rsp=IDLE,failure=null)[HttpParser{s=CLOSED,0 of -1}]]<-DecryptedEndPoint@193ff18c{api.kucoin.com/13.113.121.24:443<->/192.168.1.100:27497,OPEN,fill=-,flush=-,to=22604/0}->HttpConnectionOverHTTP@571103e6(l:/192.168.1.100:27497 <-> r:api.kucoin.com/13.113.121.24:443,closed=false)=>HttpChannelOverHTTP@a423e61(exchange=HttpExchange@e7dbbf1 req=TERMINATED/null@null res=PENDING/null@null)[send=HttpSenderOverHTTP@4b7f345a(req=QUEUED,snd=COMPLETED,failure=null)[HttpGenerator@61d4e46c{s=START}],recv=HttpReceiverOverHTTP@7a7e7f01(rsp=IDLE,failure=null)[HttpParser{s=CLOSED,0 of -1}]]->SocketChannelEndPoint@2b50cb15{api.kucoin.com/13.113.121.24:443<->/192.168.1.100:27497,ISHUT,fill=-,flush=-,to=21603/0}{io=0/0,kio=0,kro=1}->SslConnection@6de1ad97{NEED_WRAP,eio=-1/-1,di=-1}=>HttpConnectionOverHTTP@571103e6(l:/192.168.1.100:27497 <-> r:api.kucoin.com/13.113.121.24:443,closed=false)=>HttpChannelOverHTTP@a423e61(exchange=HttpExchange@e7dbbf1 req=TERMINATED/null@null res=PENDING/null@null)[send=HttpSenderOverHTTP@4b7f345a(req=QUEUED,snd=COMPLETED,failure=null)[HttpGenerator@61d4e46c{s=START}],recv=HttpReceiverOverHTTP@7a7e7f01(rsp=IDLE,failure=null)[HttpParser{s=CLOSED,0 of -1}]] at java.util.concurrent.CompletableFuture.encodeRelay(CompletableFuture.java:326) at java.util.concurrent.CompletableFuture.completeRelay(CompletableFuture.java:338) at java.util.concurrent.CompletableFuture.uniRelay(CompletableFuture.java:911) at java.util.concurrent.CompletableFuture$UniRelay.tryFire(CompletableFuture.java:899) at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:474) at java.util.concurrent.CompletableFuture.completeExceptionally(CompletableFuture.java:1977) at com.myapplication.ResponseListener.onComplete(ResponseListener.java:45) at org.eclipse.jetty.client.ResponseNotifier.notifyComplete(ResponseNotifier.java:193) at org.eclipse.jetty.client.ResponseNotifier.notifyComplete(ResponseNotifier.java:185) at org.eclipse.jetty.client.HttpReceiver.terminateResponse(HttpReceiver.java:464) at org.eclipse.jetty.client.HttpReceiver.abort(HttpReceiver.java:545) at org.eclipse.jetty.client.HttpReceiver.responseFailure(HttpReceiver.java:436) at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.failAndClose(HttpReceiverOverHTTP.java:369) at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.earlyEOF(HttpReceiverOverHTTP.java:338) at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:1476) at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.shutdown(HttpReceiverOverHTTP.java:209) at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.process(HttpReceiverOverHTTP.java:147) at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.receive(HttpReceiverOverHTTP.java:73) at org.eclipse.jetty.client.http.HttpChannelOverHTTP.receive(HttpChannelOverHTTP.java:133) at org.eclipse.jetty.client.http.HttpConnectionOverHTTP.onFillable(HttpConnectionOverHTTP.java:155) at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:281) at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:102) at org.eclipse.jetty.io.ssl.SslConnection.onFillable(SslConnection.java:291) at org.eclipse.jetty.io.ssl.SslConnection$3.succeeded(SslConnection.java:151) at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:102) at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:118) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:333) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:310) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:168) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:126) at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:366) at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:760) at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:678) ... 1 common frames omitted Caused by: java.io.EOFException: HttpConnectionOverHTTP@571103e6(l:/192.168.1.100:27497 <-> r:api.kucoin.com/13.113.121.24:443,closed=false)=>HttpChannelOverHTTP@a423e61(exchange=HttpExchange@e7dbbf1 req=TERMINATED/null@null res=PENDING/null@null)[send=HttpSenderOverHTTP@4b7f345a(req=QUEUED,snd=COMPLETED,failure=null)[HttpGenerator@61d4e46c{s=START}],recv=HttpReceiverOverHTTP@7a7e7f01(rsp=IDLE,failure=null)[HttpParser{s=CL
问题根源分析
这种偶发的EOFException通常由以下几种情况导致:
- 服务端(api.kucoin.com)因负载过高、内部错误或超时策略,在未完整返回响应时就主动关闭了连接
- 网络波动、防火墙拦截等外部因素导致连接中途断开
- Jetty客户端的连接复用机制出现问题,复用了已经失效的长连接
- Jetty版本较老,存在连接处理相关的已知bug
具体解决方案
1. 配置合理的超时参数
Jetty默认的超时设置可能不足以应对网络不稳定的场景,你可以明确设置连接超时、空闲超时和请求读取超时:
// 初始化HttpClient时设置全局超时 HttpClient httpClient = new HttpClient(); httpClient.setConnectTimeout(5000); // 连接超时5秒 httpClient.setIdleTimeout(10000); // 连接空闲超过10秒就关闭 httpClient.start(); // 针对单个请求设置读取超时 Request request = httpClient.newRequest("https://api.kucoin.com/your-api-path") .timeout(15000, TimeUnit.MILLISECONDS); // 15秒内未收到完整响应则超时
2. 启用连接池健康检查
Jetty的连接池可能会复用已经失效的连接,开启健康检查可以在复用前验证连接状态:
HttpClient httpClient = new HttpClient(); httpClient.getPool().setHealthCheck((connection, callback) -> { // 发送HEAD请求验证连接可用性 connection.send(new Request.Head("/"), result -> { callback.succeeded(result.isSucceeded()); }); });
3. 添加异常重试逻辑
因为异常是偶发的,你可以在代码中捕获EOFException并进行有限次数的重试(注意避免无限重试):
public CompletableFuture<ContentResponse> sendWithRetry(Request request, int maxRetries) { return request.send() .exceptionally(ex -> { if (ex.getCause() instanceof EOFException && maxRetries > 0) { // 重试时需要重新创建请求对象,避免状态污染 Request newRequest = httpClient.newRequest(request.getURI()) .method(request.getMethod()) .headers(request.getHeaders()); return sendWithRetry(newRequest, maxRetries - 1).join(); } throw new CompletionException(ex); }); }
4. 升级Jetty版本
你使用的Jetty 9.4.10是2018年的老版本,后续的9.4.x版本修复了大量连接处理的bug,建议升级到9.4.x的最新稳定版(比如9.4.52.v20230823),这能从根本上减少这类偶发问题。
5. 排查服务端侧问题
如果条件允许,可以联系kucoin的技术支持,或者查看他们的开发者文档,确认是否有特定的请求限制、超时设置,或者是否存在服务端侧的不稳定情况。
内容的提问来源于stack exchange,提问作者Gili
相关产品推荐
相关产品推荐

