RestTemplate整合OkHttp3如何实现gzip响应的透明处理?
问题根本原因
你当前配置未实现自动gzip解压的核心原因是:手动在拦截器添加了Accept-Encoding: gzip请求头。OkHttp默认自带透明gzip处理能力,但只要检测到用户主动设置了Accept-Encoding头,就会判定用户需要自行处理解压逻辑,自动停用内置的透明解压功能。
最优透明处理方案(和Apache HttpClient效果完全一致)
OkHttp默认就支持透明gzip,只需要移除手动加请求头的逻辑,显式指定使用OkHttp作为请求工厂即可,上层业务代码不需要任何修改,完全无感知:
1. 依赖保持不变
保留你当前的okhttp依赖即可,无需新增额外依赖:
<dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> </dependency>
2. 修改RestTemplate Bean配置
@Bean public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) { // 可自定义OkHttpClient配置(超时、连接池等,不影响透明gzip功能) OkHttpClient okHttpClient = new OkHttpClient.Builder() .connectTimeout(Duration.ofSeconds(10)) .readTimeout(Duration.ofSeconds(30)) .build(); // 构造OkHttp3请求工厂 OkHttp3ClientHttpRequestFactory requestFactory = new OkHttp3ClientHttpRequestFactory(okHttpClient); return restTemplateBuilder .rootUri(_endpoint) // 移除你之前手动添加Accept-Encoding头的拦截器! .requestFactory(() -> requestFactory) .build(); }
该方案的效果和你使用Apache HttpClient完全一致:OkHttp会自动在请求中添加Accept-Encoding: gzip头,收到响应后自动解压,同时移除响应中的Content-Encoding、Content-Length头,上层完全感知不到压缩的存在,实现完全透明处理。
备用方案:必须手动设置Accept-Encoding时的透明处理
如果你的业务场景必须手动控制Accept-Encoding头的添加,可以通过拦截器实现自动解压,也能达到透明效果:
自定义gzip解压拦截器
public class GzipDecompressInterceptor implements ClientHttpRequestInterceptor { @Override public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { // 你可以在这里手动添加Accept-Encoding头 request.getHeaders().add(HttpHeaders.ACCEPT_ENCODING, "gzip"); ClientHttpResponse originalResponse = execution.execute(request, body); // 检测响应是否为gzip压缩,是则自动解压 String contentEncoding = originalResponse.getHeaders().getFirst(HttpHeaders.CONTENT_ENCODING); if (contentEncoding != null && contentEncoding.contains("gzip")) { return new ClientHttpResponse() { @Override public HttpStatus getStatusCode() throws IOException { return originalResponse.getStatusCode(); } @Override public int getRawStatusCode() throws IOException { return originalResponse.getRawStatusCode(); } @Override public String getStatusText() throws IOException { return originalResponse.getStatusText(); } @Override public void close() { originalResponse.close(); } @Override public InputStream getBody() throws IOException { return new GZIPInputStream(originalResponse.getBody()); } @Override public HttpHeaders getHeaders() { HttpHeaders headers = new HttpHeaders(); headers.putAll(originalResponse.getHeaders()); // 移除压缩相关头,上层无感知 headers.remove(HttpHeaders.CONTENT_ENCODING); headers.remove(HttpHeaders.CONTENT_LENGTH); return headers; } }; } return originalResponse; } }
将拦截器添加到RestTemplate
@Bean public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) { OkHttpClient okHttpClient = new OkHttpClient.Builder().build(); OkHttp3ClientHttpRequestFactory requestFactory = new OkHttp3ClientHttpRequestFactory(okHttpClient); return restTemplateBuilder .rootUri(_endpoint) .requestFactory(() -> requestFactory) .additionalInterceptors(new GzipDecompressInterceptor()) .build(); }
内容的提问来源于stack exchange,提问作者wxh
相关产品推荐
相关产品推荐

