RestTemplate 401 异常解析失败问题解决方案
当使用 RestTemplate 默认构造器时,处理 401 等错误响应时常常会遇到无法正确获取响应体的问题。这是因为默认的请求工厂实现存在一定的局限性。
问题原因分析
RestTemplate 默认使用SimpleClientHttpRequestFactory,它基于 JDK 的HttpURLConnection实现。当遇到 401 等错误状态码时:
1 2 3
| if (response.getStatusCode().isError()) { InputStream inputStream = response.getBody(); }
|
SimpleClientHttpResponse的getBody()方法实现存在问题:
1 2 3 4 5 6 7
| @Override public InputStream getBody() throws IOException { InputStream errorStream = this.connection.getErrorStream(); this.responseStream = (errorStream != null ? errorStream : this.connection.getInputStream()); return this.responseStream; }
|
此时调用getInputStream()会抛出IOException,导致无法获取错误响应体。这是因为 JDK 的HttpURLConnection在处理 401 等认证错误时,不会将响应体通过getErrorStream()返回,而是直接抛出异常。
解决方案
解决这个问题的方法是更换 RestTemplate 的请求工厂,使用 Apache 的 HttpClient 实现:
1 2
| RestTemplate restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory());
|
使用HttpComponentsClientHttpRequestFactory的优势:
- 能正确处理 401 等错误响应的响应体
- 提供更丰富的 HTTP 特性支持
- 更好的连接池管理
- 更灵活的超时设置
完整示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| import org.apache.http.client.HttpClient; import org.apache.http.impl.client.HttpClients; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.web.client.RestTemplate;
@Configuration public class RestTemplateConfig {
@Bean public RestTemplate restTemplate() { HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); requestFactory.setConnectTimeout(5000); requestFactory.setReadTimeout(5000); return new RestTemplate(requestFactory); } public void useRestTemplate() { RestTemplate restTemplate = restTemplate(); try { org.springframework.http.ResponseEntity<String> response = restTemplate.getForEntity("https://api.example.com/protected-resource", String.class); if (response.getStatusCode().is2xxSuccessful()) { String body = response.getBody(); } else { String errorBody = response.getBody(); } } catch (org.springframework.web.client.HttpStatusCodeException e) { String errorBody = e.getResponseBodyAsString(); int statusCode = e.getRawStatusCode(); } } }
|
依赖配置
使用HttpComponentsClientHttpRequestFactory需要添加 Apache HttpClient 依赖:
1 2 3 4 5
| <dependency> <groupId>org.apache.httpcomponents.client5</groupId> <artifactId>httpclient5</artifactId> <version>5.3</version> </dependency>
|
Gradle:
1
| implementation 'org.apache.httpcomponents.client5:httpclient5:5.3'
|
总结
通过替换 RestTemplate 的请求工厂为HttpComponentsClientHttpRequestFactory,可以解决 401 等错误响应解析失败的问题,同时获得更强大的 HTTP 客户端功能。这是在生产环境中使用 RestTemplate 的推荐配置方式
v1.3.10