关注点分离之RestTemplate的错误处理

xiaoxiao2025-11-20  6

作者:JackieTang  

来源:生活点亮技术

1. 概览

在这个简短的教程中,将讨论如何实现一个自定义ResponseErrorHandler类并将其注入到RestTemplate实例中去,这样我们就可以在调用远程API时优雅地处理HTTP错误。

2. 默认的错误处理器

默认情况下,如果出现HTTP错误,RestTemplate将抛出下面所列的某一个异常:

HttpClientErrorException –如果HTTP状态码为4 xx

HttpServerErrorException –如果HTTP状态码为5xx

UnknownHttpStatusCodeException –如果是一个未知的HTTP状态码

所有上面的异常类都继承了RestClientResponseException。

显然,添加自定义错误处理的最简单策略,是将调用逻辑嵌在try/catch块中。然后,我们根据需要,来处理捕获的异常。

但是,如果远程API的个数增加或单个API被多个地方调用,相应的try/catch块也会随之增加,即这个简单的策略并不具有很好的扩展性。如果我们所有的远程调用都复用一个错误处理器,那就会更高效。

3. 实现一个自定义ResponseErrorHandler

根据上面的需求,我们下面要实现的自定义ResponseErrorHandler,应该能够从响应中读取HTTP状态,并且:

抛出一个对我们的应用程序有意义的异常

简单处理,即直接忽略HTTP状态码,并让响应流连续不中断

并且,实现ResponseErrorHandler接口的自定义处理器需要注入到RestTemplate实例中。 具体而言,我们需要使用RestTemplateBuilder来构建RestTemplate,并在响应流中替换DefaultResponseErrorHandler。

那么,让我们先来创建一个自定义处理器RestTemplateResponseErrorHandler吧:

@Component

public class RestTemplateResponseErrorHandler

 implements ResponseErrorHandler {

   @Override

   public boolean hasError(ClientHttpResponse httpResponse)

     throws IOException {

       return (

         httpResponse.getStatusCode().series() == CLIENT_ERROR

         || httpResponse.getStatusCode().series() == SERVER_ERROR);

   }

   @Override

   public void handleError(ClientHttpResponse httpResponse)

     throws IOException {

       if (httpResponse.getStatusCode()

         .series() == HttpStatus.Series.SERVER_ERROR) {

           // handle SERVER_ERROR

       } else if (httpResponse.getStatusCode()

         .series() == HttpStatus.Series.CLIENT_ERROR) {

           // handle CLIENT_ERROR

           if (httpResponse.getStatusCode() == HttpStatus.NOT_FOUND) {

               throw new NotFoundException();

           }

       }

   }

}

接下来,我们使用RestTemplateBuilder来初始化RestTemplate实例,这样就可以加载前面创建的RestTemplateResponseErrorHandler类:

@Service

public class BarConsumerService {

   private RestTemplate restTemplate;

   @Autowired

   public BarConsumerService(RestTemplateBuilder restTemplateBuilder) {

       RestTemplate restTemplate = restTemplateBuilder

         .errorHandler(new RestTemplateResponseErrorHandler())

         .build();

   }

   public Bar fetchBarById(String barId) {

       return restTemplate.getForObject("/bars/4242", Bar.class);

   }

}

4. 测试处理器

最后,让我们通过mock一个服务器,并让服务器返回一个NOT_FOUND HTTP状态码来测试这个自定义处理器:

@RunWith(SpringRunner.class)

@ContextConfiguration(classes = { NotFoundException.class, Bar.class })

@RestClientTest

public class RestTemplateResponseErrorHandlerIntegrationTest {

   @Autowired

   private MockRestServiceServer server;

   @Autowired

   private RestTemplateBuilder builder;

   @Test(expected = NotFoundException.class)

   public void  givenRemoteApiCall_when404Error_thenThrowNotFound() {

       Assert.assertNotNull(this.builder);

       Assert.assertNotNull(this.server);

       RestTemplate restTemplate = this.builder

         .errorHandler(new RestTemplateResponseErrorHandler())

         .build();

       this.server

         .expect(ExpectedCount.once(), requestTo("/bars/4242"))

         .andExpect(method(HttpMethod.GET))

         .andRespond(withStatus(HttpStatus.NOT_FOUND));

       Bar response = restTemplate

         .getForObject("/bars/4242", Bar.class);

       this.server.verify();

   }

}

5. 总结

本文提供了一个解决方案,用于实现和测试RestTemplate的自定义错误处理器,该处理器可以将HTTP错误转换为有意义的异常。

与往常一样,本文中提供的代码可以在Github上找到。

原文链接:https://www.baeldung.com/spring-rest-template-error-handling

作者: baeldung

译者:helloworldtang

-END-

 近期热文:

Swagger中配置了@ApiModelProperty的allowableValues属性但不显示的问题

为什么Kafka中的分区数只能增加不能减少?

一文带你吃透线程池

设计一个百万级的消息推送系统

Hmily:高性能异步分布式事务TCC框架

并行化:你的高并发大杀器

Spring Boot整合 Sentry 监控项目日志

重磅:Elasticsearch上市!市值近50亿美元

利用SPRING管理热加载的GROOVY对象!

Spring Boot中如何扩展XML请求和响应的支持

Java 11正式发布,新特性解读

关注我

点击“阅读原文”,看本号其他精彩内容

转载请注明原文地址: https://www.6miu.com/read-5039977.html

最新回复(0)