Spring RestTemplate Fehlerbehandlung

Fehlerbehandlung für Spring RestTemplate

1. Überblick

In diesem kurzen Tutorial wird erläutert, wie dieResponseErrorHandler-Schnittstelle in einerRestTemplate-Instanz implementiert und eingefügt wird, um HTTP-Fehler, die von Remote-APIs zurückgegeben werden, ordnungsgemäß zu behandeln. 

2. Standardfehlerbehandlung

Standardmäßig löstRestTemplate im Falle eines HTTP-Fehlers eine dieser Ausnahmen aus:

  1. HttpClientErrorException - bei HTTP-Status 4xx

  2. HttpServerErrorException – in Fall des HTTP-Status 5xx

  3. UnknownHttpStatusCodeException – in Fall eines unbekannten HTTP-Status

Alle diese Ausnahmen sind Erweiterungen vonRestClientResponseException.

Obviously, the simplest strategy to add a custom error handling is to wrap the call in a try/catch block. Dann verarbeiten wir die abgefangene Ausnahme nach Belieben.

this simple strategy doesn’t scale well nimmt jedoch mit zunehmender Anzahl von Remote-APIs oder -Aufrufen zu. Es wäre effizienter, wenn wir einen wiederverwendbaren Fehlerbehandler für alle unsere Remote-Anrufe implementieren könnten.

3. Implementierung einesResponseErrorHandler

Eine Klasse, dieResponseErrorHandler will implementiert, liest den HTTP-Status aus der Antwort und entweder:

  1. Wirf eine Ausnahme aus, die für unsere Anwendung von Bedeutung ist

  2. Ignorieren Sie einfach den HTTP-Status und lassen Sie den Antwortfluss ohne Unterbrechung weiterlaufen

Wir müssen die Implementierung vonResponseErrorHandlerin die Instanz vonRestTemplateeinfügen.

Daher verwenden wirRestTemplateBuilder, um die Vorlage zu erstellen undDefaultResponseErrorHandler im Antwortfluss zu ersetzen.

Implementieren wir also zuerst unsereRestTemplateResponseErrorHandler:

@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();
            }
        }
    }
}

Als nächstes erstellen wir die InstanzRestTemplatemitRestTemplateBuilder to , um unsereRestTemplateResponseErrorHandler: einzuführen

@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. Testen unserer Implementierung

Testen Sie diesen Handler abschließend, indem Sie einen Server verspotten und den Status einesNOT_FOUNDzurückgeben:

@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. Fazit

In diesem Artikel wurde eine Lösung zum Implementieren und Testen eines benutzerdefinierten Fehlerbehandlers fürRestTemplate vorgestellt, der HTTP-Fehler in sinnvolle Ausnahmen konvertiert.

Wie immer ist der in diesem Artikel vorgestellte Codeover on Github verfügbar.