RestTemplate 发送 JSON 请求时为何要手动序列化对象?
在使用 RestTemplate
发送 HTTP 请求时,我们经常会遇到这样的问题:直接传递 Java 对象作为请求体可能会导致请求失败,而改为 手动序列化为 JSON 字符串 后,接口才能正常接收。这篇文章将深入解析 为什么 RestTemplate
需要手动序列化 JSON,以及推荐的最佳实践。
1. 直接传递 Java 对象可能导致的问题
通常,我们可能会这样写代码:
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HkRequest request = new HkRequest();
request.setEndDate("2024-03-12");
HttpEntity<HkRequest> entity = new HttpEntity<>(request, headers);
ResponseEntity<BaseResponse<HkData>> response = restTemplate.exchange(
marketingReturnUrl + "/channel/hk",
HttpMethod.POST,
entity,
new ParameterizedTypeReference<BaseResponse<HkData>>() {}
);
乍一看,这段代码是符合 RestTemplate
规范的,但在某些情况下,它可能会 无法正确序列化 request
对象,从而导致请求失败。主要原因有:
RestTemplate
可能解析为application/x-www-form-urlencoded
而非application/json
HttpMessageConverter
可能无法正确转换对象,特别是当HkRequest
不是标准的可序列化 POJO 时- 如果
HkRequest
内部包含复杂类型(如Date
、List<T>
等),Spring 可能无法正确处理
2. 解决方案:手动序列化为 JSON 字符串
为了确保 RestTemplate
发送的请求体是符合 application/json
规范的,我们可以手动将 Java 对象转换为 JSON 字符串:
✅ 推荐方式 1:使用 FastJSON 进行手动序列化
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HkRequest request = new HkRequest();
request.setEndDate("2024-03-12");
// 手动序列化对象为 JSON 字符串
HttpEntity<String> entity = new HttpEntity<>(JSON.toJSONString(request), headers);
ResponseEntity<BaseResponse<HkData>> response = restTemplate.exchange(
marketingReturnUrl + "/channel/hk",
HttpMethod.POST,
entity,
new ParameterizedTypeReference<BaseResponse<HkData>>() {}
);
✅ 推荐方式 2:使用 Jackson 进行手动序列化
ObjectMapper objectMapper = new ObjectMapper();
String jsonRequest = objectMapper.writeValueAsString(request);
HttpEntity<String> entity = new HttpEntity<>(jsonRequest, headers);
✅ 推荐方式 3:确保 RestTemplate
自动处理 JSON
在某些情况下,如果 RestTemplate
能正确识别 HttpMessageConverter
,可以直接使用 Java 对象:
HttpEntity<HkRequest> entity = new HttpEntity<>(request, headers);
⚠️ 但这需要确保 Jackson
依赖存在,并且 HkRequest
是标准的 POJO,否则可能导致解析失败!
3. RestTemplate
默认的 HttpMessageConverter
Spring RestTemplate
默认使用 MappingJackson2HttpMessageConverter
(如果 Jackson
依赖存在),但在某些情况下:
RestTemplate
可能 未能正确加载 JSON 转换器- Spring 可能会 将对象转换为
application/x-www-form-urlencoded
,而不是application/json
手动转换为 JSON 字符串可以 避免这些潜在的问题。
4. 总结:最佳实践
方式 | 适用情况 | 是否推荐 |
---|---|---|
JSON.toJSONString(request) | FastJSON 环境,手动序列化 | ✅ 推荐 |
ObjectMapper.writeValueAsString(request) | Jackson 生态,手动序列化 | ✅ 推荐 |
HttpEntity<>(request, headers) | 仅当 RestTemplate 默认支持 JSON 序列化 | ⚠️ 可能有问题 |
✅ 最佳实践:手动转换 JSON 字符串,避免 RestTemplate
误解析,确保 Content-Type
为 application/json
!