Spring Boot中如何不捕获异常处理RestTemplate响应码?
当然可以实现!不过得先修正两个关键问题
你的思路完全没问题——不想靠异常捕获来处理409,而是直接判断响应状态码,这在RestTemplate里是可以做到的,但需要先调整RestTemplate的默认行为,同时修正状态码的判断方式。
为什么你原来的代码不生效?
RestTemplate默认会把所有4xx和5xx状态码都当成错误抛出异常,所以你直接调用postForEntity时,遇到409就会进入HttpClientErrorException的捕获块,根本走不到后面的if判断。另外result.getStatusCode()=="409"的写法也不对,getStatusCode()返回的是HttpStatus枚举类型,不是字符串,直接用字符串比较永远不会成立。
正确实现步骤
1. 自定义RestTemplate的错误处理器,让4xx状态码正常返回
我们需要修改RestTemplate的默认错误处理逻辑,让它只把5xx服务器错误当成异常抛出,4xx(包括409)都正常返回响应实体:
RestTemplate restTemplate = new RestTemplate(); restTemplate.setErrorHandler(new DefaultResponseErrorHandler() { @Override protected boolean hasError(HttpStatus statusCode) { // 仅将5xx状态码视为错误,4xx全部正常返回 return statusCode.is5xxServerError(); } });
2. 规范判断409状态码
用HttpStatus.CONFLICT(这是409对应的枚举常量)来判断,比直接写数字更规范、可读性更强。
完整的Controller代码
@PostMapping("/todos/{toDoNoteId}/users") public ResponseEntity<String> postUser(@RequestBody User user, @PathVariable int toDoNoteId, UriComponentsBuilder builder) throws HttpMessageNotReadableException, ParseException { RestTemplate restTemplate = new RestTemplate(); // 配置错误处理器,让4xx状态码不抛出异常 restTemplate.setErrorHandler(new DefaultResponseErrorHandler() { @Override protected boolean hasError(HttpStatus statusCode) { return statusCode.is5xxServerError(); } }); final String uri = "http://friend:5000/users"; ResponseEntity<String> result = restTemplate.postForEntity(uri, user, String.class); if (HttpStatus.CONFLICT.equals(result.getStatusCode())) { // 这里写用户已存在的处理逻辑,比如返回自定义提示或原响应体 return ResponseEntity.status(HttpStatus.CONFLICT).body("该用户已存在"); } else { // 处理其他状态码的逻辑 return result; } }
优化建议:把RestTemplate配置成全局Bean
如果你的项目里多处用到RestTemplate,建议把它配置成Spring Bean,统一设置错误处理器,避免重复代码:
@Configuration public class RestTemplateConfig { @Bean public RestTemplate restTemplate() { RestTemplate restTemplate = new RestTemplate(); restTemplate.setErrorHandler(new DefaultResponseErrorHandler() { @Override protected boolean hasError(HttpStatus statusCode) { return statusCode.is5xxServerError(); } }); return restTemplate; } }
然后在Controller里直接注入使用即可:
@Autowired private RestTemplate restTemplate; @PostMapping("/todos/{toDoNoteId}/users") public ResponseEntity<String> postUser(@RequestBody User user, @PathVariable int toDoNoteId, UriComponentsBuilder builder) throws HttpMessageNotReadableException, ParseException { final String uri = "http://friend:5000/users"; ResponseEntity<String> result = restTemplate.postForEntity(uri, user, String.class); if (HttpStatus.CONFLICT.equals(result.getStatusCode())) { return ResponseEntity.status(HttpStatus.CONFLICT).body("该用户已存在"); } else { return result; } }
内容的提问来源于stack exchange,提问作者Svajunas Kavaliauskas
相关产品推荐
相关产品推荐

