You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用RestTemplate调用外部API时处理多JSON响应映射问题

处理RestTemplate调用外部API时的不同响应结构问题

你当前直接使用restTemplate.getForObject()的写法,会在外部API返回错误结构JSON时因字段不匹配抛出序列化异常,无法正常映射到CountResponse。可以通过以下两种思路解决:

思路1:扩展DTO兼容两种响应结构

修改原有CountResponse,新增错误字段,让它能同时接收成功和错误响应:

@Data
public class CountResponse {
    @JsonProperty(value = "PendingCount")
    private int pendingCount;
    @JsonProperty(value = "todayPendingCount")
    private int todayPendingCount;
    // 新增错误字段,匹配无数据时的响应结构
    private String error;
}

然后改用restTemplate.exchange()获取完整响应体,手动解析处理:

public ResponseEntity<CountResponse> count(@Validated @RequestBody CountRequest homeRequest) {
    String uri = "http://localhost:8089/abc?email=" + homeRequest.getEmail();
    try {
        // 先获取原始响应字符串,避免直接序列化失败
        ResponseEntity<String> responseEntity = restTemplate.exchange(
                uri,
                HttpMethod.GET,
                null,
                String.class
        );
        
        ObjectMapper objectMapper = new ObjectMapper();
        CountResponse result = objectMapper.readValue(responseEntity.getBody(), CountResponse.class);
        
        // 判断是否存在错误信息
        if (result.getError() != null) {
            // 无数据时返回对应状态码,比如404
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(result);
        }
        return ResponseEntity.ok(result);
    } catch (RestClientException | JsonProcessingException e) {
        // 处理调用或解析异常
        CountResponse errorResult = new CountResponse();
        errorResult.setError("调用外部API失败:" + e.getMessage());
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResult);
    }
}

思路2:分别定义成功/错误DTO,动态解析

如果不想修改原有CountResponse,可以单独定义错误响应DTO:

@Data
public class ErrorResponse {
    private String error;
}

然后在控制器中优先尝试解析为成功DTO,失败则切换为错误DTO解析:

public ResponseEntity<?> count(@Validated @RequestBody CountRequest homeRequest) {
    String uri = "http://localhost:8089/abc?email=" + homeRequest.getEmail();
    try {
        ResponseEntity<String> responseEntity = restTemplate.exchange(
                uri,
                HttpMethod.GET,
                null,
                String.class
        );
        String responseBody = responseEntity.getBody();
        ObjectMapper objectMapper = new ObjectMapper();
        
        // 优先尝试解析成功响应
        try {
            CountResponse countResponse = objectMapper.readValue(responseBody, CountResponse.class);
            return ResponseEntity.ok(countResponse);
        } catch (JsonProcessingException e) {
            // 解析失败,尝试解析错误响应
            ErrorResponse errorResponse = objectMapper.readValue(responseBody, ErrorResponse.class);
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errorResponse);
        }
    } catch (RestClientException e) {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("调用外部API失败:" + e.getMessage());
    }
}

关键注意点

  • 不要直接用getForObject():该方法会自动强制序列化到目标类,一旦结构不匹配就抛出异常,无法适配多结构响应场景。
  • 用exchange()拿原始响应体:手动控制序列化逻辑,才能灵活处理不同结构的JSON。
  • 结合状态码判断:如果外部API在无数据时返回非2xx状态码(比如404),还可以用ResponseErrorHandler统一处理;但如果返回2xx状态码,必须手动解析响应体判断内容。

内容的提问来源于stack exchange,提问作者vegeta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 00:47:42