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

Spring Boot3.2.2与Apache HttpClient5下Logbook拦截器测试异常修复方法

修复Spring Boot 3.2.2 + Logbook 3.5.0 下的 UnsupportedOperationException 问题

核心原因

Spring Framework 6.1重构了HttpComponentsClientHttpRequest,原有的EntityUtils.toByteArray()方式会触发不可重复读取的流抛出UnsupportedOperationException,而Logbook 3.5.0尚未适配这个变更。

解决方案

1. 优先升级Logbook版本

Logbook在3.6.0及后续版本中已经修复了与Spring Framework 6.1的兼容问题,直接升级依赖即可:

  • Maven:
<dependency>
    <groupId>org.zalando</groupId>
    <artifactId>logbook-spring-boot-starter</artifactId>
    <version>3.7.0</version>
</dependency>
  • Gradle:
implementation 'org.zalando:logbook-spring-boot-starter:3.7.0'

升级后无需修改业务代码,即可解决流读取的兼容性问题。

2. 临时适配(无法升级Logbook时)

如果暂时不能升级Logbook,需要修改自定义MDC处理逻辑,避免直接读取HttpEntity的字节数组:

  • 自定义ClientHttpRequestInterceptor时,替换EntityUtils.toByteArray(entity)的逻辑,改用HttpEntity.writeTo()将内容写入临时输出流,同时保留MDC上下文填充:
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
    // 原有MDC填充逻辑保留
    MdcService.fillContext(request);
    
    // 替换EntityUtils.toByteArray的逻辑
    if (request instanceof HttpEntityRequest) {
        HttpEntity<?> entity = ((HttpEntityRequest) request).getHttpEntity();
        if (entity != null && entity.getBody() != null) {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            entity.writeTo(baos);
            // 后续如果需要使用请求体,用baos.toByteArray()
        }
    }
    
    return execution.execute(request, body);
}
  • 若使用Logbook的自定义配置,需覆盖LogbookHttpRequest的内容读取逻辑,确保使用writeTo而非直接读取字节数组。

3. 测试环境临时方案

针对测试场景,可以:

  • 使用MockRestServiceServer模拟HTTP请求,绕过真实的HttpComponentsClientHttpRequest实例;
  • 自定义一个可重复读取的HttpEntity包装类,包装原请求实体,让EntityUtils.toByteArray()能正常获取内容:
public class RepeatableHttpEntity<T> extends HttpEntity<T> {
    private final byte[] content;

    public RepeatableHttpEntity(T body, HttpHeaders headers) throws IOException {
        super(body, headers);
        if (body instanceof InputStreamSource) {
            this.content = EntityUtils.toByteArray((HttpEntity<T>) this);
        } else {
            this.content = null;
        }
    }

    @Override
    public void writeTo(OutputStream outputStream) throws IOException {
        if (content != null) {
            outputStream.write(content);
        } else {
            super.writeTo(outputStream);
        }
    }
}

在测试中使用该类包装请求实体,避免流读取异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 16:40:08