好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

RestTemplate自定义ErrorHandler方式

RestTemplate自定义ErrorHandler

当通过RestTemplate调用服务发生异常时,往往会返回400 Bad Request或500 internal error等错误信息。如果想捕捉服务本身抛出的异常信息,需要通过自行实现RestTemplate的ErrorHandler。

RestTemplate实例

可以通过调用setErrorHandler方法设置ErrorHandler,实现对请求响应异常的判别和处理。自定义的ErrorHandler需实现ResponseErrorHandler接口,同时Spring boot也提供了默认实现DefaultResponseErrorHandler,因此也可以通过继承该类来实现自己的ErrorHandler。

getForObject和postForObject方法调用底层doExecute方法来执行HTTP请求,通过Spring boot中doExecute方法可以看到RestTemplate在进行HTTP请求时分成了

三个步骤:

1)创建请求,获取响应;

2)判断响应是否异常,处理异常

3)将响应消息体封装为java对象

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

Object varl4;

// 1 创建请求,获取响应

ClientHttpRequest request = this .createRequest(url, method);

if (requestCallback != null ) {

     requestCallback.doWithRequest(request);

}

response = request.execute();

 

// 2 判断响应是否存在异常,处理异常

this .handleResponse(url, method, response);

 

// 3 将响应消息体封装为java对象

if (responseExtractor == null ) {

    resource = null ;

    return resource;

}

var14 = responseExtractor.extractData(response);

在handleResponse方法中对调用ErrorHandler来判断响应是否异常,并处理异常。这里需要注意的是,如果自定义ErrorHandler中的handlerError方法中获取了response中body内容就需要抛出异常,防止doExecute方法继续执行responseExtractor.extractData(response)语句导致response.body(类型为inputstream)被重复读取。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

protected void handleResponse(URI url, HttpMethod method, ClientHttpResponse response) throws IOException {

     ResponseErrorHandler errorHandler = this .getErrorHandler();

     boolean hasError = errorHandler.hasError(response);

     if ( this .logger.isDebugEnabled()) {

         try {

             this .logger.debug(method.name() + " request for \"" + url + "\" resulted in " + response.getRawStatusCode() + " (" + response.getStatusText() + ")" + (hasError ? "; invoking error handler" : "" ));

         } catch (IOException var7) {

             ;

         }

     }

     if (hasError) {

         errorHandler.handleError(url, method, response);

     }

}

学习了ErrorHandler在RestTemplate中的调用,开始实现自定义的ErrorHandler。首先创建自定义异常(由于ResponseErrorHandler中定义了handlerError方法抛出IOException,因此自定义的异常只能为RuntimeException)

?

1

2

3

4

5

6

7

8

public class MyException extends RuntimeException {

     public MyException(String message){

         super (message);

     }

     public MyException(String message, Throwable e){

         super (message + e.getLocalizedMessage());

     }

}

实现自定义ErrorHandler,一种思路是根据响应消息体进行相应的异常处理策略,对于其他异常情况由父类DefaultResponseErrorHandler来进行处理。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

public class MyErrorHandler extends DefaultResponseErrorHandler {

     @Override

      public boolean hasError(ClientHttpResponse response) throws IOException{

         return super .hasError(response);

     }

 

     @Override

     public void handleError(ClientHttpResponse response) throws IOException{

         Scanner scanner = new Scanner(response.getBody()).useDelimiter( "\\A" );

         String stringResponse = scanner.hasNext() ? scanner.next() : "" ;

         if (stringResponse.matches( ".*XXX.*" )){

             throw new MyException(stringResponse);

         }

         else {

             super .handleError(response);

         }

     }

}

SpringBoot 中使用 RestTemplate 自定义 异常处理,捕获最原始的错误信息

一些 API 的报错信息通过 Response 的 body返回。

使用 HttpClient 能正常获取到 StatusCode 和 body 中的错误提示。然而使用 RestTemplate ,会直接抛出下面的异常。

如果想获取原始的信息并进一步处理会比较麻烦。

类似下面这种404、403响应码直接抛出异常并不是我们想要的

org.springframework.web.client.HttpClientErrorException: 404 null
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:94)
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:79)
at org.springframework.web.client.ResponseErrorHandler.handleError(ResponseErrorHandler.java:63)
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:777)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:730)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:704)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:621)

RestTemplate 异常处理流程

下面看一下原因, RestTemplate 中的 getForObject, getForEntity 和 exchange 等常用方法最终都是调用 doExecute 方法。下面是 doExecute 方法源码:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

public class RestTemplate extends InterceptingHttpAccessor implements RestOperations {

     private ResponseErrorHandler errorHandler;

     ......   

     @Nullable

     protected <T> T doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor) throws RestClientException {

         Assert.notNull(url, "'url' must not be null" );

         Assert.notNull(method, "'method' must not be null" );

         ClientHttpResponse response = null ;

         String resource;

         try {

             ClientHttpRequest request = this .createRequest(url, method);

             if (requestCallback != null ) {

                 requestCallback.doWithRequest(request);

             }

 

             response = request.execute();

             // 处理 Response

             this .handleResponse(url, method, response);

             if (responseExtractor != null ) {

                 Object var14 = responseExtractor.extractData(response);

                 return var14;

             }

 

             resource = null ;

         } catch (IOException var12) {

             resource = url.toString();

             String query = url.getRawQuery();

             resource = query != null ? resource.substring( 0 , resource.indexOf( 63 )) : resource;

             throw new ResourceAccessException( "I/O error on " + method.name() + " request for \"" + resource + "\": " + var12.getMessage(), var12);

         } finally {

             if (response != null ) {

                 response.close();

             }

         }

         return resource;

     }

     protected void handleResponse(URI url, HttpMethod method, ClientHttpResponse response) throws IOException {

         ResponseErrorHandler errorHandler = this .getErrorHandler();

         boolean hasError = errorHandler.hasError(response);

         if ( this .logger.isDebugEnabled()) {

             try {

                 this .logger.debug(method.name() + " request for \"" + url + "\" resulted in " + response.getRawStatusCode() + " (" + response.getStatusText() + ")" + (hasError ? "; invoking error handler" : "" ));

             } catch (IOException var7) {

                 ;

             }

         }

         // 异常处理

         if (hasError) {

             errorHandler.handleError(url, method, response);

         }

     }

}

从下面的代码可以看出,DefaultResponseErrorHandler 捕获并抛出了异常。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

public class DefaultResponseErrorHandler implements ResponseErrorHandler {

     ...   

     protected void handleError(ClientHttpResponse response, HttpStatus statusCode) throws IOException {

         switch (statusCode.series()) {

         case CLIENT_ERROR:

             throw new HttpClientErrorException(statusCode, response.getStatusText(), response.getHeaders(), this .getResponseBody(response), this .getCharset(response));

         case SERVER_ERROR:

             throw new HttpServerErrorException(statusCode, response.getStatusText(), response.getHeaders(), this .getResponseBody(response), this .getCharset(response));

         default :

             throw new UnknownHttpStatusCodeException(statusCode.value(), response.getStatusText(), response.getHeaders(), this .getResponseBody(response), this .getCharset(response));

         }

     }

}

如果想自己捕获异常信息,自己处理异常的话可以通过实现 ResponseErrorHandler 类来实现。其源码如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

public interface ResponseErrorHandler {

 

     // 标示 Response 是否存在任何错误。实现类通常会检查 Response 的 HttpStatus。

     boolean hasError(ClientHttpResponse var1) throws IOException;

 

     // 处理 Response 中的错误, 当 HasError 返回 true 时才调用此方法。

     void handleError(ClientHttpResponse var1) throws IOException;

 

     // handleError 的替代方案,提供访问请求URL和HTTP方法的额外信息。

     default void handleError(URI url, HttpMethod method, ClientHttpResponse response) throws IOException {

         this .handleError(response);

     }

}

自定义 RestTemplate 异常处理

如果想像 HttpClient 一样直接从 Response 获取 HttpStatus 和 body 中的报错信息 而不抛出异常,可以通过下面的代码实现:

?

1

2

3

4

5

6

7

8

9

10

public class CustomErrorHandler implements ResponseErrorHandler {

     @Override

     public boolean hasError(ClientHttpResponse response) throws IOException {

         return true ;

     }

     @Override

     public void handleError(ClientHttpResponse response) throws IOException {

 

     }

}

设置 RestTemplate 的异常处理类

?

1

2

3

restTemplate.setErrorHandler( new CustomErrorHandler());

ResponseEntity<String> response = restTemplate.exchange(uri, HttpMethod.GET, null , String. class );

System.out.println(response.getBody());

输出结果

{"code":404,"result":null,"message":"Resources not found"}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。

原文链接:https://blog.csdn.net/zju611/article/details/80206207

查看更多关于RestTemplate自定义ErrorHandler方式的详细内容...

  阅读:11次