作者: baeldung
译者:helloworldtang
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吧:
代码语言:javascript复制@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类:
代码语言:javascript复制@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状态码来测试这个自定义处理器:
代码语言:javascript复制@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上找到。