Обработка ошибок Spring RestTemplate

Spring RestTemplate Обработка ошибок

1. обзор

В этом коротком руководстве мы обсудим, как реализовать и внедрить интерфейсResponseErrorHandler в экземплярRestTemplate - для корректной обработки ошибок HTTP, возвращаемых удаленными API. 

2. Обработка ошибок по умолчанию

По умолчаниюRestTemplate выдает одно из этих исключений в случае ошибки HTTP:

  1. HttpClientErrorException - в случае HTTP-статуса 4xx

  2. HttpServerErrorException – in случай статуса HTTP 5xx

  3. UnknownHttpStatusCodeException – in случай неизвестного статуса HTTP

Все эти исключения являются расширениямиRestClientResponseException.

Obviously, the simplest strategy to add a custom error handling is to wrap the call in a try/catch block. Затем мы обрабатываем пойманное исключение по своему усмотрению.

Однакоthis simple strategy doesn’t scale well по мере увеличения количества удаленных API или вызовов. Было бы более эффективно, если бы мы могли реализовать многоразовый обработчик ошибок для всех наших удаленных вызовов.

3. РеализацияResponseErrorHandler

Итак, класс, реализующийResponseErrorHandler will, считывает статус HTTP из ответа и либо:

  1. Добавьте исключение, которое имеет значение для нашего приложения

  2. Просто игнорируйте статус HTTP и позвольте потоку ответа продолжаться без прерывания

Нам нужно внедрить реализациюResponseErrorHandler в экземплярRestTemplate.

Следовательно, мы используемRestTemplateBuilder для создания шаблона и заменяем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();
            }
        }
    }
}

Затем мы создаем экземплярRestTemplate, используяRestTemplateBuilder to , вводим наш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. Тестирование нашей реализации

Наконец, давайте протестируем этот обработчик, имитируя сервер и возвращая статусNOT_FOUND:

@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 в значимые исключения.

Как всегда, доступен код, представленный в этой статьеover on Github.