0%

restTemplate解析401异常失败

RestTemplate 401 异常解析失败问题解决方案

当使用 RestTemplate 默认构造器时,处理 401 等错误响应时常常会遇到无法正确获取响应体的问题。这是因为默认的请求工厂实现存在一定的局限性。

问题原因分析

RestTemplate 默认使用SimpleClientHttpRequestFactory,它基于 JDK 的HttpURLConnection实现。当遇到 401 等错误状态码时:

1
2
3
if (response.getStatusCode().isError()) { // 4XX或者5XX
InputStream inputStream = response.getBody();
}

SimpleClientHttpResponsegetBody()方法实现存在问题:

1
2
3
4
5
6
7
@Override
public InputStream getBody() throws IOException {
// 当响应码为401时,getErrorStream()可能返回null
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
// 添加Apache HttpClient依赖后
RestTemplate restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory());

使用HttpComponentsClientHttpRequestFactory的优势:

  1. 能正确处理 401 等错误响应的响应体
  2. 提供更丰富的 HTTP 特性支持
  3. 更好的连接池管理
  4. 更灵活的超时设置

完整示例

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替代默认工厂
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 的推荐配置方式

欢迎关注我的其它发布渠道

表情 | 预览
快来做第一个评论的人吧~
Powered By Valine
v1.3.10