RestTemplate处理HttpClientErrorException如何提取目标错误消息
问题根因
当前代码捕获HttpClientErrorException后直接调用异常自带的getMessage()方法构造新异常抛出,该方法默认会拼接状态码+完整下游响应体内容,而下游返回的响应体本身包含时间戳、路径等多余字段,最终就导致外层返回的消息包含冗余内容。
可行解决方案
方案1:当前业务代码直接解析响应体
适合仅这一处接口有提取核心错误消息需求的场景,直接在现有catch块中解析错误响应体的message字段即可,示例如下(以Jackson解析为例):
// 项目中一般已自动注册ObjectMapper,直接注入即可 @Autowired private ObjectMapper objectMapper; public void validateOtps (ValidateOtpRequestDto requestDto, String otpId){ try{ HttpEntity<ValidateOtpRequestDto> requestEntity = new HttpEntity<>(requestDto); restTemplate.exchange(authServiceUrl + "/authentication-service/otps/" + otpId, HttpMethod.POST, requestEntity, String.class); }catch (HttpClientErrorException e){ log.error("OTP校验请求失败,响应内容:{}", e.getResponseBodyAsString()); String errorMsg = "OTP校验失败"; try { // 解析下游返回的错误JSON,提取核心message JsonNode errorNode = objectMapper.readTree(e.getResponseBodyAsString()); if (errorNode.has("message")) { errorMsg = errorNode.get("message").asText(); } } catch (JsonProcessingException parseEx) { log.error("解析错误响应失败", parseEx); } // 用提取到的核心消息构造异常抛出 throw new HttpClientErrorException(e.getStatusCode(), errorMsg); } catch (Exception e){ log.error("OTP校验异常", e); } }
方案2:自定义RestTemplate错误处理器统一处理
适合多处使用RestTemplate调用同一外部服务的场景,一次配置全局生效,无需每个接口重复写解析逻辑:
- 首先自定义错误处理器实现
ResponseErrorHandler接口:
public class AuthServiceErrorHandler implements ResponseErrorHandler { private final ObjectMapper objectMapper = new ObjectMapper(); @Override public boolean hasError(ClientHttpResponse response) throws IOException { // 判断是否为错误响应 return response.getStatusCode().isError(); } @Override public void handleError(ClientHttpResponse response) throws IOException { String responseBody = StreamUtils.copyToString(response.getBody(), StandardCharsets.UTF_8); String errorMsg = "服务调用失败"; try { JsonNode errorNode = objectMapper.readTree(responseBody); if (errorNode.has("message")) { errorMsg = errorNode.get("message").asText(); } } catch (Exception e) { // 解析失败时使用默认错误消息即可 } throw new HttpClientErrorException(response.getStatusCode(), errorMsg); } }
- 配置RestTemplate使用自定义错误处理器:
@Bean public RestTemplate authServiceRestTemplate() { RestTemplate restTemplate = new RestTemplate(); restTemplate.setErrorHandler(new AuthServiceErrorHandler()); return restTemplate; }
后续所有调用认证服务的逻辑都注入这个自定义配置的RestTemplate即可,所有错误都会自动提取核心消息。
方案3:全局异常处理器统一处理
如果项目已经使用@RestControllerAdvice做全局异常拦截,也可以在全局层统一处理HttpClientErrorException,统一转换返回格式:
@RestControllerAdvice public class GlobalExceptionHandler { private final ObjectMapper objectMapper = new ObjectMapper(); @ExceptionHandler(HttpClientErrorException.class) public ResponseEntity<Map<String, Object>> handleHttpCallError(HttpClientErrorException e) { Map<String, Object> result = new HashMap<>(); result.put("status", e.getStatusCode().value()); result.put("error", null); String errorMsg = "请求失败"; try { JsonNode errorNode = objectMapper.readTree(e.getResponseBodyAsString()); if (errorNode.has("message")) { errorMsg = errorNode.get("message").asText(); } } catch (Exception parseEx) { // 解析失败使用默认消息 } result.put("message", errorMsg); return new ResponseEntity<>(result, e.getStatusCode()); } }
内容的提问来源于stack exchange,提问作者Devin Farial
相关产品推荐
相关产品推荐

