BufferedReader读取最后一行时卡顿约15秒的问题排查
问题分析与解决方案:Apache HttpClient 读取分块响应时的延迟问题
问题原因
你遇到的15秒延迟,核心原因是服务器未正确发送分块编码的结束标记,或者连接未被及时关闭,导致客户端的readLine()一直阻塞等待数据,直到触发HttpClient的默认超时(15秒正是常见的默认超时值)。
虽然Apache HttpClient的getContent()确实会自动处理Transfer-Encoding: chunked的响应,但分块编码要求服务器必须发送一个长度为0的块来标记流的结束。如果服务器遗漏了这个结束块,客户端的输入流会一直处于等待状态,直到连接超时断开,才会让readLine()返回null。
另外你的代码存在冗余操作:InputStreamReader被BufferedReader包装后,try-with-resources在关闭br时会自动关闭底层的isr,手动调用isr.close()属于重复操作,可能引发不必要的资源问题。
解决方案
1. 使用HttpClient工具类简化读取(推荐)
直接用EntityUtils工具类读取响应内容,它会自动处理分块编码、流关闭和异常,彻底避免阻塞问题:
// 替换原有的流读取逻辑 String responseBody = EntityUtils.toString(entityResp, StandardCharsets.UTF_8); System.out.println(responseBody); System.out.println("End of stream reached....."); // 确保释放实体资源 EntityUtils.consume(entityResp);
2. 调整HttpClient超时配置
如果必须手动处理流,可以通过配置缩短超时时间,避免长时间阻塞:
// 构建自定义请求配置 RequestConfig requestConfig = RequestConfig.custom() .setSocketTimeout(5000) // 读取超时设为5秒 .setConnectTimeout(5000) // 连接超时设为5秒 .build(); // 初始化带超时配置的HttpClient CloseableHttpClient httpClient = HttpClientBuilder.create() .setDefaultRequestConfig(requestConfig) .build();
3. 修复代码中的流关闭冗余
删除手动关闭isr的代码,将isr也放入try-with-resources中统一管理:
//PRINT OUT String line; try(InputStreamReader isr = new InputStreamReader(entityResp.getContent()); BufferedReader br = new BufferedReader(isr)){ System.out.println("Before BufferedReader loop"); while((line = br.readLine()) != null){ System.out.println(line); } System.out.println("End of stream reached....."); } System.out.println("After try with resources");
分块数据处理说明
当Content-Length为-1时,说明响应采用分块编码,HttpClient会自动解析分块结构:
- 每个分块包含长度头和对应的数据内容
- 最后一个分块必须是长度为0的空块,用于标记响应结束
如果服务器未发送这个结束块,客户端就会持续等待。这种情况下,要么推动服务器端修复响应格式,要么通过设置合理的超时时间来避免无限阻塞。
内容的提问来源于stack exchange,提问作者Trevor Pastrami
相关产品推荐
相关产品推荐

