为何我的自定义ClientHttpRequestInterceptor会返回空响应?
排查自定义HttpLoggingInterceptor返回空响应的问题
我帮你定位下这个问题——你的拦截器出现空响应,十有八九是因为读取响应体后没有重置输入流导致的,具体原因和解决办法如下:
核心原因
Java的InputStream(也就是响应体的输入流)是一次性读取的:当你在logResponse方法里直接读取response.getBody()的内容后,流的指针会移动到末尾,后续实际业务代码再去读取这个响应体时,就会读到空数据,最终返回空响应。而且Spring默认的ClientHttpResponse实现并不支持重置输入流,所以直接读取后就没法恢复数据了。
解决办法:包装响应体为可重复读取的缓冲流
我们可以用Spring提供的BufferedClientHttpResponseWrapper来包装原始响应,这个类会把响应体缓存到内存中,让输入流可以被多次读取。修改你的拦截器代码如下:
import org.springframework.web.client.BufferedClientHttpResponseWrapper; import org.springframework.util.StreamUtils; import java.nio.charset.StandardCharsets; public class HttpLoggingInterceptor implements ClientHttpRequestInterceptor { private final static Logger log = LoggerFactory.getLogger(HttpLoggingInterceptor.class); @Override public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { logRequest(request, body); ClientHttpResponse originalResponse = execution.execute(request, body); // 用缓冲包装器包装响应,实现可重复读取 BufferedClientHttpResponseWrapper bufferedResponse = new BufferedClientHttpResponseWrapper(originalResponse); // 读取缓冲后的响应体打日志 logResponse(bufferedResponse); // 返回包装后的响应,后续业务代码可以正常读取响应体 return bufferedResponse; } private void logResponse(ClientHttpResponse response) throws IOException { // 读取响应体,因为是缓冲包装的,后续还能再读 byte[] responseBodyBytes = StreamUtils.copyToByteArray(response.getBody()); String responseBody = new String(responseBodyBytes, StandardCharsets.UTF_8); log.info("Response Status: {}, Headers: {}, Body: {}", response.getStatusCode(), response.getHeaders(), responseBody); } // 你的logRequest方法保持不变(示例实现供参考) private void logRequest(HttpRequest request, byte[] body) { String requestBody = new String(body, StandardCharsets.UTF_8); log.info("Request Method: {}, URI: {}, Headers: {}, Body: {}", request.getMethod(), request.getURI(), request.getHeaders(), requestBody); } }
额外注意点
- 确保你的
logResponse方法使用的是包装后的BufferedClientHttpResponseWrapper实例,这样每次调用getBody()都会返回一个新的、指向流开头的输入流。 - 如果你的响应体非常大,内存缓冲可能会有OOM风险,这种情况可以考虑只记录响应元数据(状态码、Headers),或者用临时文件来缓冲,但一般业务场景下内存缓冲足够用。
内容的提问来源于stack exchange,提问作者maya16
相关产品推荐
相关产品推荐

