RestTemplate 401 异常解析失败问题解决方案
当使用 RestTemplate 默认构造器时,处理 401 等错误响应时常常会遇到无法正确获取响应体的问题。这是因为默认的请求工厂实现存在一定的局限性。
问题原因分析
RestTemplate 默认使用SimpleClientHttpRequestFactory,它基于 JDK 的HttpURLConnection实现。当遇到 401 等错误状态码时:
if (response.getStatusCode().isError()) {
InputStream inputStream = response.getBody();
}
SimpleClientHttpResponse的getBody()方法实现存在问题:
@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 实现:
RestTemplate restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory());
使用HttpComponentsClientHttpRequestFactory的优势:
- 能正确处理 401 等错误响应的响应体
- 提供更丰富的 HTTP 特性支持
- 更好的连接池管理
- 更灵活的超时设置
完整示例
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 依赖:
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.3</version>
</dependency>
Gradle:
implementation 'org.apache.httpcomponents.client5:httpclient5:5.3'
总结
通过替换 RestTemplate 的请求工厂为HttpComponentsClientHttpRequestFactory,可以解决 401 等错误响应解析失败的问题,同时获得更强大的 HTTP 客户端功能。这是在生产环境中使用 RestTemplate 的推荐配置方式