在 Spring Boot 中使用 RestTemplate 处理响应的核心是选择合适的请求方法 (如 getForObject/getForEntity/exchange),并根据响应类型(字符串、实体类、复杂集合、自定义格式)进行解析,同时处理响应状态码、响应头和异常。以下是分场景的详细讲解,覆盖 90% 实际开发需求:
一、核心响应处理方法对比
RestTemplate 提供了 3 类核心方法处理响应,需根据需求选择:
| 方法类型 | 示例(GET) | 特点 | 适用场景 |
|---|---|---|---|
xxxForObject |
getForObject(...) |
直接返回响应体(忽略状态码/响应头),解析失败直接抛异常 | 只关心响应体、场景简单 |
xxxForEntity |
getForEntity(...) |
返回 ResponseEntity<T>,包含响应体+状态码+响应头+响应Cookie |
需要获取状态码/响应头 |
exchange |
exchange(...) |
通用方法,支持所有 HTTP 方法,可自定义请求头,解析复杂类型更灵活 | 复杂场景(如解析 List/嵌套JSON) |
注:
xxxForObject/xxxForEntity有 GET/POST/PUT/DELETE 对应方法(如postForObject/deleteForEntity),exchange是万能方法,适配所有场景。
二、基础响应处理场景
场景 1:解析响应为字符串(快速调试/未知响应结构)
适用于调试阶段,先获取原始响应字符串,再分析结构:
java
@Service
public class ResponseService {
@Autowired
private RestTemplate restTemplate;
// 解析响应为 String
public String getResponseAsString() {
String url = "http://localhost:8081/user/1";
// getForObject 直接返回字符串
String rawResponse = restTemplate.getForObject(url, String.class);
System.out.println("原始响应:" + rawResponse);
return rawResponse;
}
}
输出示例(JSON 字符串):
原始响应:{"id":1,"username":"张三","age":25}
场景 2:解析响应为自定义实体类(最常用)
将 JSON 响应自动映射到实体类(基于 Jackson 序列化,需保证字段名匹配):
java
// 1. 定义响应实体类(与目标服务返回的 JSON 字段对应)
@Data // Lombok 注解,省略 getter/setter
public class UserDTO {
private Long id;
private String username;
private Integer age;
// 字段名不一致时,用 @JsonProperty 映射
@JsonProperty("create_time")
private LocalDateTime createTime;
}
// 2. 解析为实体类
public UserDTO getResponseAsEntity() {
String url = "http://localhost:8081/user/1";
// 方式1:getForObject 直接返回实体类
UserDTO user = restTemplate.getForObject(url, UserDTO.class);
// 方式2:getForEntity 获取完整响应(含状态码)
ResponseEntity<UserDTO> responseEntity = restTemplate.getForEntity(url, UserDTO.class);
UserDTO userFromEntity = responseEntity.getBody(); // 提取响应体
HttpStatus statusCode = responseEntity.getStatusCode(); // 获取状态码(如 200 OK)
int statusCodeValue = responseEntity.getStatusCodeValue(); // 状态码数值(200)
System.out.println("状态码:" + statusCode + ",用户信息:" + userFromEntity);
return user;
}
输出示例:
状态码:200 OK,用户信息:UserDTO(id=1, username=张三, age=25, createTime=2025-12-05T10:00:00)
三、进阶响应处理场景
场景 1:获取响应头/响应Cookie
通过 ResponseEntity 可获取响应头(如 Token、Content-Type)、Cookie 等元数据:
java
public void getResponseHeaderAndCookie() {
String url = "http://localhost:8081/user/1";
ResponseEntity<UserDTO> response = restTemplate.getForEntity(url, UserDTO.class);
// 1. 获取单个响应头(如 Token)
String token = response.getHeaders().getFirst("X-Token");
System.out.println("响应头 Token:" + token);
// 2. 获取所有响应头
HttpHeaders headers = response.getHeaders();
headers.forEach((key, values) -> {
System.out.println(key + ":" + String.join(",", values));
});
// 3. 获取响应Cookie(如需)
List<String> cookieHeaders = headers.get(HttpHeaders.SET_COOKIE);
if (cookieHeaders != null) {
System.out.println("响应Cookie:" + cookieHeaders);
}
}
输出示例:
响应头 Token:abc123456
Content-Type:application/json
Transfer-Encoding:chunked
响应Cookie:JSESSIONID=789abc; Path=/; HttpOnly
场景 2:解析响应为 List/复杂集合
getForObject 无法直接解析 List<T>(会报类型转换异常),需用 exchange + ParameterizedTypeReference:
java
// 解析响应为 List<UserDTO>
public List<UserDTO> getResponseAsList() {
String url = "http://localhost:8081/user?pageNum=1&pageSize=10";
// 定义泛型类型(ParameterizedTypeReference 解决泛型擦除问题)
ParameterizedTypeReference<List<UserDTO>> typeRef = new ParameterizedTypeReference<List<UserDTO>>() {};
// exchange 通用方法:URL + 请求方法 + 请求体(GET 为 null) + 泛型类型
ResponseEntity<List<UserDTO>> response = restTemplate.exchange(
url,
HttpMethod.GET,
null, // GET 请求无请求体,传 null
typeRef
);
List<UserDTO> userList = response.getBody();
System.out.println("用户列表:" + userList);
return userList;
}
场景 3:解析嵌套 JSON 响应(如分页结果)
若响应是嵌套结构(如分页数据),需定义匹配的嵌套实体类:
json
// 目标服务返回的分页响应
{
"code": 200,
"msg": "success",
"data": {
"list": [{"id":1,"username":"张三"}, {"id":2,"username":"李四"}],
"total": 100,
"pageNum": 1,
"pageSize": 10
}
}
定义嵌套实体类:
java
// 外层响应类
@Data
public class PageResponse<T> {
private Integer code;
private String msg;
private PageData<T> data; // 嵌套的分页数据
}
// 分页数据类
@Data
public class PageData<T> {
private List<T> list;
private Long total;
private Integer pageNum;
private Integer pageSize;
}
解析嵌套响应:
java
public PageResponse<UserDTO> getNestedResponse() {
String url = "http://localhost:8081/user/page?pageNum=1&pageSize=10";
// 定义嵌套泛型类型
ParameterizedTypeReference<PageResponse<UserDTO>> typeRef = new ParameterizedTypeReference<PageResponse<UserDTO>>() {};
ResponseEntity<PageResponse<UserDTO>> response = restTemplate.exchange(
url,
HttpMethod.GET,
null,
typeRef
);
PageResponse<UserDTO> pageResponse = response.getBody();
System.out.println("总条数:" + pageResponse.getData().getTotal());
System.out.println("用户列表:" + pageResponse.getData().getList());
return pageResponse;
}
场景 4:处理非 JSON 响应(如 XML、表单)
RestTemplate 默认内置 JSON 转换器(MappingJackson2HttpMessageConverter),如需处理 XML/表单,需添加对应消息转换器:
步骤 1:引入 XML 依赖(如需解析 XML)
xml
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
步骤 2:配置消息转换器
java
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
// 获取默认消息转换器列表
List<HttpMessageConverter<?>> converters = restTemplate.getMessageConverters();
// 1. 添加 XML 转换器(支持解析 XML 响应)
converters.add(new MappingJackson2XmlHttpMessageConverter());
// 2. (可选)添加表单转换器(解析 application/x-www-form-urlencoded 响应)
converters.add(new FormHttpMessageConverter());
restTemplate.setMessageConverters(converters);
return restTemplate;
}
步骤 3:解析 XML 响应
java
// 假设目标服务返回 XML 响应:<UserDTO><id>1</id><username>张三</username></UserDTO>
public UserDTO getXmlResponse() {
String url = "http://localhost:8081/user/xml/1";
ResponseEntity<UserDTO> response = restTemplate.getForEntity(url, UserDTO.class);
return response.getBody();
}
四、响应异常处理
RestTemplate 会根据响应状态码抛出异常,需捕获并处理(避免程序崩溃):
1. 异常类型说明
| 异常类型 | 触发场景 |
|---|---|
HttpClientErrorException |
4xx 状态码(如 400 入参错误、404 资源不存在、401 未授权) |
HttpServerErrorException |
5xx 状态码(如 500 服务端错误、503 服务不可用) |
ResourceAccessException |
连接超时、拒绝连接、DNS 解析失败等(网络问题) |
RestClientException |
所有 RestTemplate 异常的父类(兜底捕获) |
2. 异常捕获示例
java
public UserDTO handleResponseException(Long userId) {
String url = "http://localhost:8081/user/{id}";
try {
ResponseEntity<UserDTO> response = restTemplate.getForEntity(url, UserDTO.class, userId);
// 主动校验状态码(可选,即使 2xx 也可自定义逻辑)
if (response.getStatusCode() != HttpStatus.OK) {
System.out.println("响应状态码异常:" + response.getStatusCode());
return null;
}
return response.getBody();
} catch (HttpClientErrorException.NotFound e) {
// 捕获 404 异常
System.out.println("用户不存在:" + e.getResponseBodyAsString());
return null;
} catch (HttpClientErrorException.Unauthorized e) {
// 捕获 401 异常
System.out.println("未授权访问:" + e.getResponseBodyAsString());
return null;
} catch (HttpServerErrorException e) {
// 捕获 5xx 异常
System.out.println("服务端错误:" + e.getStatusCode() + ",原因:" + e.getResponseBodyAsString());
return null;
} catch (ResourceAccessException e) {
// 捕获网络超时/连接失败
System.out.println("服务连接失败:" + e.getMessage());
return null;
} catch (RestClientException e) {
// 兜底捕获所有 RestTemplate 异常
System.out.println("请求失败:" + e.getMessage());
return null;
}
}
五、自定义响应解析配置
1. 设置响应编码(解决中文乱码)
若响应中文乱码,需自定义消息转换器的编码:
java
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
// 遍历默认转换器,修改 JSON 转换器的编码为 UTF-8
for (HttpMessageConverter<?> converter : restTemplate.getMessageConverters()) {
if (converter instanceof MappingJackson2HttpMessageConverter) {
((MappingJackson2HttpMessageConverter) converter).setDefaultCharset(StandardCharsets.UTF_8);
}
}
return restTemplate;
}
2. 忽略响应状态码异常(仅特殊场景)
若不想让 RestTemplate 抛出 4xx/5xx 异常,可自定义 ResponseErrorHandler:
java
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
// 自定义错误处理器:不抛出异常
restTemplate.setErrorHandler(new ResponseErrorHandler() {
@Override
public boolean hasError(ClientHttpResponse response) throws IOException {
// 所有状态码都视为"无错误",不抛出异常
return false;
}
@Override
public void handleError(ClientHttpResponse response) throws IOException {
// 空实现,不处理错误
}
});
return restTemplate;
}
注意:此配置需手动校验状态码,否则会忽略真实错误,仅适用于需兼容非标准状态码的场景。
总结
RestTemplate 处理响应的核心思路:
- 简单场景 :用
xxxForObject直接解析响应体(String/实体类); - 需状态码/响应头 :用
xxxForEntity获取ResponseEntity; - 复杂结构(List/嵌套) :用
exchange+ParameterizedTypeReference; - 异常处理 :捕获
HttpClientErrorException/ResourceAccessException等,分场景处理; - 自定义解析:通过消息转换器适配 XML/表单,或调整编码解决乱码。
根据实际需求选择对应方法,优先保证异常处理和类型解析的准确性,避免因泛型擦除、状态码未校验导致的问题。