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

OkHttp调用chain.proceed时出现连接关闭异常该如何解决?

异常根因

OkHttp 的 ResponseBody 是绑定了网络IO流的一次性可消费资源,只要调用过 bytes()、string()、charStream() 等消费方法,或是主动调用了 close() 方法,底层流就会被永久关闭,后续再尝试读取就会抛出 IllegalStateException: closed 异常。从你提供的异常栈可以明确看到,报错触发点是拦截器中调用了 ResponseBody.bytes() 方法消费了响应体,后续下游逻辑再读响应体时就触发了该异常。

你修改方法参数类型的操作对解决该问题没有任何作用,这是OkHttp响应流的设计规则,和参数类名无关。

解决方法

如果需要在拦截器中读取响应体做校验,不能直接消费原始响应的body,需要先读取body的副本,避免影响下游使用。OkHttp 提供了 peekBody() 方法可以直接返回响应体的拷贝,读取拷贝不会影响原始响应的流状态。

同时注意不要在拦截器中捕获所有异常后返回null,OkHttp要求拦截器必须返回合法的Response对象,返回null会引发额外的空指针异常。

修改后的参考代码如下:

@Slf4j
@RequiredArgsConstructor
public class AuthHeaderInterceptor implements Interceptor {

    private final String headerKey;
    private final String headerValue;

    @Override
    public Response intercept(final Interceptor.Chain chain) throws IOException {
        final Request requestWithAuthHeader = chain.request().newBuilder()
                .header(this.headerKey, this.headerValue)
                .build();

        final Response originalResponse = chain.proceed(requestWithAuthHeader);

        // 读取响应头不会触发流关闭,可正常操作
        final String signatureHeader = originalResponse.headers().get("x-signature");
        log.info("x-signature={}", signatureHeader);
        
        // 读取响应体要操作拷贝的副本,不影响原始响应流
        ResponseBody copiedBody = originalResponse.peekBody(Long.MAX_VALUE);
        // 在这里做你的body校验逻辑,比如读取bytes或者string
        byte[] bodyBytes = copiedBody.bytes();
        log.info("响应体长度:{}", bodyBytes.length);

        // 直接返回原始响应即可,下游仍可正常读取body
        return originalResponse;
    }
}

注意事项

如果你的响应体体积特别大,peekBody() 会将全量响应体加载到内存中,可能引发OOM风险,这种场景建议改用流式读取校验的方案,无需加载全量body到内存。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 22:00:04