restcontrolleradvice manejo excepciones example error controlleradvice spring rest exception-handling resttemplate

example - spring boot manejo de excepciones



Spring Resttemplate manejo de excepciones (9)

A continuación se muestra el fragmento de código; Básicamente, estoy tratando de propagar la excepción cuando el código de error no es 200.

ResponseEntity<Object> response = restTemplate.exchange(url.toString().replace("{version}", version), HttpMethod.POST, entity, Object.class); if(response.getStatusCode().value()!= 200){ logger.debug("Encountered Error while Calling API"); throw new ApplicationException(); }

Sin embargo, en el caso de una respuesta 500 del servidor obtengo la excepción

org.springframework.web.client.HttpServerErrorException: 500 Internal Server Error at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:94) ~[spring-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]

¿Realmente necesito envolver el método de intercambio de plantillas de descanso en try? ¿Cuál sería entonces el propósito de los códigos?


Aquí está mi método POST con HTTPS que devuelve un cuerpo de respuesta para cualquier tipo de malas respuestas.

public String postHTTPSRequest(String url,String requestJson) { //SSL Context CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(new NoopHostnameVerifier()).build(); HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); requestFactory.setHttpClient(httpClient); //Initiate REST Template RestTemplate restTemplate = new RestTemplate(requestFactory); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); //Send the Request and get the response. HttpEntity<String> entity = new HttpEntity<String>(requestJson,headers); ResponseEntity<String> response; String stringResponse = ""; try { response = restTemplate.postForEntity(url, entity, String.class); stringResponse = response.getBody(); } catch (HttpClientErrorException e) { stringResponse = e.getResponseBodyAsString(); } return stringResponse; }


Debería detectar una excepción HttpStatusCodeException :

try { restTemplate.exchange(...); } catch (HttpStatusCodeException exception) { int statusCode = exception.getStatusCode().value(); ... }


Desea crear una clase que implemente ResponseErrorHandler y luego usar una instancia para establecer el manejo de errores de su plantilla de descanso:

public class MyErrorHandler implements ResponseErrorHandler { @Override public void handleError(ClientHttpResponse response) throws IOException { // your error handling here } @Override public boolean hasError(ClientHttpResponse response) throws IOException { ... } } [...] public static void main(String args[]) { RestTemplate restTemplate = new RestTemplate(); restTemplate.setErrorHandler(new MyErrorHandler()); }

Además, Spring tiene la clase DefaultResponseErrorHandler , que puede extender en lugar de implementar la interfaz, en caso de que solo desee anular el método handleError .

public class MyErrorHandler extends DefaultResponseErrorHandler { @Override public void handleError(ClientHttpResponse response) throws IOException { // your error handling here } }

Eche un vistazo a su código fuente para tener una idea de cómo Spring maneja los errores HTTP.


Ninguno de estos u otros tutoriales en otro lugar funcionó para mí. RestTemplate es simplemente una mierda. Estoy escribiendo esto para que otros consideren no perder el tiempo en esta cosa horrible. Llamo a restTemplate.exchange y obtengo el código de estado 400. También se lanza una excepción en esa línea, pero no es una HttpStatusCodeException, es una ResourceAccessException. He intentado intercambiar por Objeto y Cadena. He intentado incluir ResponseErrorHandler, que es totalmente inútil.

Tampoco es la primera vez que no puedo hacer lo que quiero con RestTemplate y ni siquiera lo he usado en mucho tiempo. No pierdas el tiempo.

Por ejemplo, puede usar:

Apache HttpClient: https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient

O OkHttp3: https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp



Si utiliza la agrupación (fábrica de clientes http) o el mecanismo de equilibrio de carga (eureka) con su RestTemplate , no tendrá el lujo de crear una new RestTemplate por clase. Si está llamando a más de un servicio, no puede usar setErrorHandler porque se usaría globalmente para todas sus solicitudes.

En este caso, la captura de HttpStatusCodeException parece ser la mejor opción.

La única otra opción que tiene es definir varias instancias de RestTemplate utilizando la anotación @Qualifier .

Además, pero este es mi propio gusto, me gusta mi manejo de errores acurrucado estrechamente a mis llamadas.


Spring lo abstrae de la muy, muy extensa lista de códigos de estado http. Esa es la idea de las excepciones. Eche un vistazo a la jerarquía org.springframework.web.client.RestClientException:

Tiene un montón de clases para mapear las situaciones más comunes cuando se trata de respuestas http. La lista de códigos http es realmente grande, no querrá escribir código para manejar cada situación. Pero, por ejemplo, eche un vistazo a la sub-jerarquía HttpClientErrorException. Tiene una única excepción para asignar cualquier tipo de error 4xx. Si necesita profundizar, entonces puede hacerlo. Pero con solo detectar HttpClientErrorException, puede manejar cualquier situación en la que se proporcionaron datos incorrectos al servicio.

DefaultResponseErrorHandler es realmente simple y sólido. Si el código de estado de respuesta no es de la familia de 2xx, simplemente devuelve verdadero para el método hasError.


Spring trata inteligentemente los códigos de error http como excepciones y asume que su código de manejo de excepciones tiene el contexto para manejar el error. Para que el intercambio funcione como lo espera, haga esto:

try { return restTemplate.exchange(url, httpMethod, httpEntity, String.class); } catch(HttpStatusCodeException e) { return ResponseEntity.status(e.getRawStatusCode()).headers(e.getResponseHeaders()) .body(e.getResponseBodyAsString()); }

Esto devolverá todos los resultados esperados de la respuesta.


El código de cambio está abajo :

public <T> ResponseEntity<T> exchange(String url, HttpMethod method, HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables) throws RestClientException

Excepción RestClientException tiene la excepción HttpClientErrorException y HttpStatusCodeException .

Por lo tanto, en RestTemplete puede HttpStatusCodeException excepción HttpClientErrorException y HttpStatusCodeException . En el objeto de excepción, puede obtener un mensaje de error exacto de esta manera: exception.getResponseBodyAsString()

Aquí está el código de ejemplo :

public Object callToRestService(HttpMethod httpMethod, String url, Object requestObject, Class<?> responseObject) { printLog( "Url : " + url); printLog( "callToRestService Request : " + new GsonBuilder().setPrettyPrinting().create().toJson(requestObject)); try { RestTemplate restTemplate = new RestTemplate(); restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter()); restTemplate.getMessageConverters().add(new StringHttpMessageConverter()); HttpHeaders requestHeaders = new HttpHeaders(); requestHeaders.setContentType(MediaType.APPLICATION_JSON); HttpEntity<Object> entity = new HttpEntity<>(requestObject, requestHeaders); long start = System.currentTimeMillis(); ResponseEntity<?> responseEntity = restTemplate.exchange(url, httpMethod, entity, responseObject); printLog( "callToRestService Status : " + responseEntity.getStatusCodeValue()); printLog( "callToRestService Body : " + new GsonBuilder().setPrettyPrinting().create().toJson(responseEntity.getBody())); long elapsedTime = System.currentTimeMillis() - start; printLog( "callToRestService Execution time: " + elapsedTime + " Milliseconds)"); if (responseEntity.getStatusCodeValue() == 200 && responseEntity.getBody() != null) { return responseEntity.getBody(); } } catch (HttpClientErrorException exception) { printLog( "callToRestService Error :" + exception.getResponseBodyAsString()); //Handle exception here }catch (HttpStatusCodeException exception) { printLog( "callToRestService Error :" + exception.getResponseBodyAsString()); //Handle exception here } return null; }

Aquí está la descripción del código :

En este método, debe pasar la clase de solicitud y respuesta. Este método analizará automáticamente la respuesta como objeto solicitado.

En primer lugar, debe agregar el convertidor de mensajes.

restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter()); restTemplate.getMessageConverters().add(new StringHttpMessageConverter());

Luego tienes que agregar requestHeader . Aquí está el código:

HttpHeaders requestHeaders = new HttpHeaders(); requestHeaders.setContentType(MediaType.APPLICATION_JSON); HttpEntity<Object> entity = new HttpEntity<>(requestObject, requestHeaders);

Finalmente, debe llamar al método de intercambio:

ResponseEntity<?> responseEntity = restTemplate.exchange(url, httpMethod, entity, responseObject);

Para la impresión prety utilicé la biblioteca Gson. aquí está el gradle: compile ''com.google.code.gson:gson:2.4''

Puede llamar al siguiente código para obtener una respuesta:

ResponseObject response=new RestExample().callToRestService(HttpMethod.POST,"URL_HERE",new RequestObject(),ResponseObject.class);

Aquí está el código de trabajo completo :

import com.google.gson.GsonBuilder; import org.springframework.http.*; import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.HttpStatusCodeException; import org.springframework.web.client.RestTemplate; public class RestExample { public RestExample() { } public Object callToRestService(HttpMethod httpMethod, String url, Object requestObject, Class<?> responseObject) { printLog( "Url : " + url); printLog( "callToRestService Request : " + new GsonBuilder().setPrettyPrinting().create().toJson(requestObject)); try { RestTemplate restTemplate = new RestTemplate(); restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter()); restTemplate.getMessageConverters().add(new StringHttpMessageConverter()); HttpHeaders requestHeaders = new HttpHeaders(); requestHeaders.setContentType(MediaType.APPLICATION_JSON); HttpEntity<Object> entity = new HttpEntity<>(requestObject, requestHeaders); long start = System.currentTimeMillis(); ResponseEntity<?> responseEntity = restTemplate.exchange(url, httpMethod, entity, responseObject); printLog( "callToRestService Status : " + responseEntity.getStatusCodeValue()); printLog( "callToRestService Body : " + new GsonBuilder().setPrettyPrinting().create().toJson(responseEntity.getBody())); long elapsedTime = System.currentTimeMillis() - start; printLog( "callToRestService Execution time: " + elapsedTime + " Milliseconds)"); if (responseEntity.getStatusCodeValue() == 200 && responseEntity.getBody() != null) { return responseEntity.getBody(); } } catch (HttpClientErrorException exception) { printLog( "callToRestService Error :" + exception.getResponseBodyAsString()); //Handle exception here }catch (HttpStatusCodeException exception) { printLog( "callToRestService Error :" + exception.getResponseBodyAsString()); //Handle exception here } return null; } private void printLog(String message){ System.out.println(message); } }

Gracias :)