Spring Resttemplate异常处理

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38093388/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 01:07:30  来源:igfitidea点击:

Spring Resttemplate exception handling

springrestexception-handlingresttemplate

提问by vaibhav

Below is the code snippet; basically, I am trying to propagate the exception when the error code is anything other than 200.

下面是代码片段;基本上,当错误代码不是 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();
            }

However in the case of a 500 response from the server I am getting the exception

但是,在来自服务器的 500 响应的情况下,我收到异常

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]

Do I really need to wrap the rest template exchange method in try? What would then be the purpose of codes?

我真的需要在 try 中包装其余的模板交换方法吗?那么代码的目的是什么?

回答by carcaret

You want to create a class that implements ResponseErrorHandlerand then use an instance of it to set the error handling of your rest template:

您想创建一个实现类,ResponseErrorHandler然后使用它的实例来设置 rest 模板的错误处理:

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

Also, Spring has the class DefaultResponseErrorHandler, which you can extend instead of implementing the interface, in case you only want to override the handleErrormethod.

此外,Spring 有 class DefaultResponseErrorHandler,您可以扩展它而不是实现接口,以防您只想覆盖该handleError方法。

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

Take a look at its source codeto have an idea of how Spring handles HTTP errors.

查看其源代码以了解 Spring 如何处理 HTTP 错误。

回答by mekazu

You should catch a HttpStatusCodeExceptionexception:

您应该捕获HttpStatusCodeException异常:

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

回答by austin cherlo

Spring cleverly treats http error codes as exceptions, and assumes that your exception handling code has the context to handle the error. To get exchange to function as you would expect it, do this:

Spring 巧妙地将 http 错误代码视为异常,并假设您的异常处理代码具有处理错误的上下文。要让交换按预期运行,请执行以下操作:

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

This will return all the expected results from the response.

这将从响应中返回所有预期结果。

回答by Investigator

Another solution is the one described here at the end of this post by "enlian": http://springinpractice.com/2013/10/07/handling-json-error-object-responses-with-springs-resttemplate

另一种解决方案是“enlian”在本文末尾描述的解决方案:http://springinpractice.com/2013/10/07/handling-json-error-object-responses-with-springs-resttemplate

try{
     restTemplate.exchange(...)
} catch(HttpStatusCodeException e){
     String errorpayload = e.getResponseBodyAsString();
     //do whatever you want
} catch(RestClientException e){
     //no response payload, tell the user sth else 
}

回答by Perimosh

Spring abstracts you from the very very very large list of http status code. That is the idea of the exceptions. Take a look into org.springframework.web.client.RestClientException hierarchy:

Spring 将您从非常非常大的 http 状态代码列表中抽象出来。这就是例外的想法。看看 org.springframework.web.client.RestClientException 层次结构:

You have a bunch of classes to map the most common situations when dealing with http responses. The http codes list is really large, you won't want write code to handle each situation. But for example, take a look into the HttpClientErrorException sub-hierarchy. You have a single exception to map any 4xx kind of error. If you need to go deep, then you can. But with just catching HttpClientErrorException, you can handle any situation where bad data was provided to the service.

在处理 http 响应时,您有一堆类来映射最常见的情况。http 代码列表非常大,您不会希望编写代码来处理每种情况。但是,例如,查看 HttpClientErrorException 子层次结构。您只有一个异常可以映射任何 4xx 类型的错误。如果你需要深入,那么你可以。但是只需捕获 HttpClientErrorException,您就可以处理向服务提供错误数据的任何情况。

The DefaultResponseErrorHandler is really simple and solid. If the response status code is not from the family of 2xx, it just returns true for the hasError method.

DefaultResponseErrorHandler 非常简单和可靠。如果响应状态代码不是来自 2xx 系列,则它只为 hasError 方法返回 true。

回答by Hannes

If you use pooling (http client factory) or load balancing (eureka) mechanism with your RestTemplate, you will not have the luxury of creating a new RestTemplateper class. If you are calling more than one service you cannot use setErrorHandlerbecause if would be globally used for all your requests.

如果您使用池(HTTP客户端工厂)或负载均衡(尤里卡)与你的机制RestTemplate,你不会有创造的豪华new RestTemplate每类。如果您正在调用多个服务,则不能使用,setErrorHandler因为 if 将全局用于您的所有请求。

In this case, catching the HttpStatusCodeExceptionseems to be the better option.

在这种情况下,捕捉HttpStatusCodeException似乎是更好的选择。

The only other option you have is to define multiple RestTemplateinstances using the @Qualifierannotation.

您唯一的其他选择是RestTemplate使用@Qualifier注释定义多个实例。

Also - but this is my own taste - I like my error handling snuggled tightly to my calls.

另外 - 但这是我自己的口味 - 我喜欢我的错误处理紧紧地依偎在我的电话上。

回答by Md. Sajedul Karim

The code of exchange is below:

兑换码如下

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

Exception RestClientExceptionhas HttpClientErrorExceptionand HttpStatusCodeExceptionexception.

除了RestClientException具有HttpClientErrorExceptionHttpStatusCodeException例外。

So in RestTempletethere may occure HttpClientErrorExceptionand HttpStatusCodeExceptionexception. In exception object you can get exact error message using this way: exception.getResponseBodyAsString()

所以在RestTemplete那里可能会发生HttpClientErrorExceptionHttpStatusCodeException异常。在异常对象中,您可以使用这种方式获得确切的错误消息:exception.getResponseBodyAsString()

Here is the example code:

这是示例代码

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

Here is the code description:

这是代码说明

In this method you have to pass request and response class. This method will automatically parse response as requested object.

在此方法中,您必须传递请求和响应类。此方法将自动将响应解析为请求的对象。

First of All you have to add message converter.

首先,您必须添加消息转换器。

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

Then you have to add requestHeader. Here is the code:

然后你必须添加requestHeader. 这是代码:

HttpHeaders requestHeaders = new HttpHeaders();
            requestHeaders.setContentType(MediaType.APPLICATION_JSON);

            HttpEntity<Object> entity = new HttpEntity<>(requestObject, requestHeaders);

Finally, you have to call exchange method:

最后,您必须调用交换方法:

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

For prety printing i used Gson library. here is the gradle : compile 'com.google.code.gson:gson:2.4'

对于漂亮的打印,我使用了 Gson 库。这是gradle:compile 'com.google.code.gson:gson:2.4'

You can just call the bellow code to get response:

您只需调用以下代码即可获得响应:

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

Here is the full working code:

这是完整的工作代码

import com.google.gson.GsonBuilder;
import org.springframework.http.*;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingHymanson2HttpMessageConverter;
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 MappingHymanson2HttpMessageConverter());
            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);
    }
}

Thanks :)

谢谢 :)

回答by Saikat

I have handled this as below:

我已处理如下:

try {
  response = restTemplate.postForEntity(requestUrl, new HttpEntity<>(requestBody, headers), String.class);
} catch (HttpStatusCodeException ex) {
  response = new ResponseEntity<String>(ex.getResponseBodyAsString(), ex.getResponseHeaders(), ex.getStatusCode());
}

回答by vkrams

Here is my POST method with HTTPS which returns a response body for any type of bad responses.

这是我使用 HTTPS 的 POST 方法,它为任何类型的错误响应返回响应正文。

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;
}