Spring RestTemplate Error Handling – Spring RestTemplate错误处理

最后修改: 2018年 5月 28日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this short tutorial, we’ll discuss how to implement and inject the ResponseErrorHandler interface in a RestTemplate instance to gracefully handle the HTTP errors returned by remote APIs.

在这个简短的教程中,我们将讨论如何在RestTemplate实例中实现和注入ResponseErrorHandler接口,以优雅地处理由远程API返回的HTTP错误。

2. Default Error Handling

2.默认的错误处理

By default, the RestTemplate will throw one of these exceptions in the case of an HTTP error:

默认情况下,RestTemplate在出现HTTP错误的情况下会抛出这些异常之一。

  1. HttpClientErrorException – in the case of HTTP status 4xx
  2. HttpServerErrorException – in the case of HTTP status 5xx
  3. UnknownHttpStatusCodeException – in the case of an unknown HTTP status

All of these exceptions are extensions of RestClientResponseException.

所有这些异常都是RestClientResponseException的扩展。

Obviously, the simplest strategy to add custom error handling is to wrap the call in a try/catch block. Then we can process the caught exception as we see fit.

显然,添加自定义错误处理的最简单策略是将调用包裹在try/catch块中。然后我们可以按照我们认为合适的方式来处理捕获的异常。

However, this simple strategy doesn’t scale well as the number of remote APIs or calls increases. It would be more efficient if we could implement a reusable error handler for all of our remote calls.

然而,随着远程API或调用数量的增加,这种简单的策略并不能很好地扩展。如果我们能够为所有的远程调用实现一个可重复使用的错误处理程序,将会更有效率。

3. Implementing a ResponseErrorHandler

3.实现一个ResponseErrorHandler

A class that implements ResponseErrorHandler will read the HTTP status from the response and either:

一个实现了ResponseErrorHandler的类将从响应中读取HTTP状态,并选择。

  1. Throw an exception that is meaningful to our application
  2. Simply ignore the HTTP status and let the response flow continue without interruption

We need to inject the ResponseErrorHandler implementation into the RestTemplate instance.

我们需要将ResponseErrorHandler实现注入到RestTemplate实例。

Thus, we can use the RestTemplateBuilder to build the template, and replace the DefaultResponseErrorHandler in the response flow.

因此,我们可以使用RestTemplateBuilder来构建模板,并替换响应流程中的DefaultResponseErrorHandler

So let’s first implement our RestTemplateResponseErrorHandler:

因此,让我们首先实现我们的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();
            }
        }
    }
}

Then we can build the RestTemplate instance using the RestTemplateBuilder to introduce our RestTemplateResponseErrorHandler:

然后我们可以使用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. Testing Our Implementation

4.测试我们的实施

Finally, we’ll test this handler by mocking a server and returning a NOT_FOUND status:

最后,我们将通过模拟一个服务器并返回一个NOT_FOUND状态来测试这个处理程序。

@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = { NotFoundException.class, Bar.class })
@RestClientTest
public class RestTemplateResponseErrorHandlerIntegrationTest {

    @Autowired 
    private MockRestServiceServer server;
 
    @Autowired 
    private RestTemplateBuilder builder;

    @Test
    public void  givenRemoteApiCall_when404Error_thenThrowNotFound() {
        Assertions.assertNotNull(this.builder);
        Assertions.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));

        Assertions.assertThrows(NotFoundException.class, () -> {
            Bar response = restTemplate.getForObject("/bars/4242", Bar.class);
        });
    }
}

5. Conclusion

5.总结

In this article, we presented a solution to implement and test a custom error handler for a RestTemplate that converts HTTP errors into meaningful exceptions.

在这篇文章中,我们提出了一个解决方案,为RestTemplate实现和测试一个自定义错误处理程序,将HTTP错误转换为有意义的异常。

As always, the code presented in this article is available over on Github.

像往常一样,本文介绍的代码可在Github上获得