前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringBoot中REST API的错误异常处理设计

SpringBoot中REST API的错误异常处理设计

作者头像
lyb-geek
发布2018-08-16 16:25:15
7K0
发布2018-08-16 16:25:15
举报
文章被收录于专栏:Linyb极客之路

RESTful API中的异常Exception处理有两个基本要求,需要明确业务意义的错误消息以及hhtp状态码。良好的错误消息能够让API客户端纠正问题。在本文中,我们将讨论并实现Spring的REST API异常处理。 Restful API错误/异常设计 在RESTful API中设计异常处理时,最好在响应中设置HTTP状态代码,这样可以表示客户端的请求为什么会失败的原因。当然也可以发送更多信息包括HTTP状态码,这些将帮助客户端迅速定位错误。 比如下面是Springboot表示/api/producer不支持post方式的错误信息:

代码语言:javascript
复制
{
    "timestamp": 1530772698787,
    "status": 405,
    "error": "Method Not Allowed",
    "exception": "org.springframework.web.HttpRequestMethodNotSupportedException",
    "message": "Request method 'POST' not supported",
    "path": "/api/producer"
}

对于我们的业务应用,应该提供更详细的有关业务的错误信息

代码语言:javascript
复制
HTTP/1.1  404
Content-Type: application/json
{
    "status": 404,
    "error_code": 123,
    "message": "Oops! It looks like that file does not exist.",
    "details": "File resource does not exist.We are working on fixing this issue.",
    "information_link": "/api/producer"
}

在设计REST API的响应时,需要理解以下重点: 1. status表示HTTP状态代码。 2. error_code表示REST API特定的错误代码。此字段有助于传递API /业务领域中特定信息。比如类似Oracle错误ORA-12345 3. message字段表示人类可读的错误消息。国际化信息 4. details部分表示完整详细信息。 5. information_link字段指定有关错误或异常的详细信息的链接。 Spring REST错误处理 Spring和Spring Boot提供了许多错误/异常处理选项。比如 @ExceptionHandler注释,@ExceptionHandler是一个Spring注释,以处理请求引发的异常。此注释在@Controller级别上起作用。

代码语言:javascript
复制
@RestController
public class WelcomeController {

    @GetMapping("/greeting")
    String greeting() throws Exception {
      //
    }

    @ExceptionHandler({Exception.class})
    public  handleException(){
       //
    }
}

该方法存在几个个问题或缺点: (1)此注释仅对指定的控制器Controller有效。 (2)这个注释不是全局的,我们需要添加到每个控制器(不是很方便)。 大多数企业应用程序都是需要扩展Spring基类的控制器(也就是通用控制器)。我们可以将@ExceptionHandler加入基类控制器,来克服上面的不便和限制,但是有以下新问题: (1)基类控制器不适用于所有类型的控制器。我们还是需要复制代码。 (2)程序员编写的控制器可能扩展不受我们控制的第三方面控制器类。 由于存在所有这些限制,因此建议不要在构建RESTful API时使用此方法 Spring的异常处理 Spring 3.2引入了@ControllerAdvice这个支持全局异常处理程序机制的注释。@ControllerAdvice可以让我们使用和上面完全相同的异常处理技术,但它是应用于整个应用程序,而不仅仅是某个控制器。看看下面的应用代码:

代码语言:javascript
复制
@ControllerAdvice
public class GlobalRestExceptionHandler extends ResponseEntityExceptionHandler {

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(Exception.class)
    public void defaultExceptionHandler() {
        // Nothing to do
    }
}

通过@ControllerAdvice和@ExceptionHandler组合,能够统一跨所有@RequestMapping方法实现集中式异常处理。这是在使用基于Spring的REST API时的一种便捷方式,因为可以指定ResponseEntity为返回值。 现在我们可以定义一下我们的错误类信息的代码,然后把这个对象嵌入ResponseEntity中返回。

代码语言:javascript
复制
public class ApiErrorResponse {

    private HttpStatus status;
    private String error_code;
    private String message;
    private String detail;

    // getter and setters
   //Builder 
    public static final class ApiErrorResponseBuilder {
        private HttpStatus status;
        private String error_code;
        private String message;
        private String detail;

        private ApiErrorResponseBuilder() {
        }

        public static ApiErrorResponseBuilder anApiErrorResponse() {
            return new ApiErrorResponseBuilder();
        }

        public ApiErrorResponseBuilder withStatus(HttpStatus status) {
            this.status = status;
            return this;
        }

        public ApiErrorResponseBuilder withError_code(String error_code) {
            this.error_code = error_code;
            return this;
        }

        public ApiErrorResponseBuilder withMessage(String message) {
            this.message = message;
            return this;
        }

        public ApiErrorResponseBuilder withDetail(String detail) {
            this.detail = detail;
            return this;
        }

        public ApiErrorResponse build() {
            ApiErrorResponse apiErrorResponse = new ApiErrorResponse();
            apiErrorResponse.status = this.status;
            apiErrorResponse.error_code = this.error_code;
            apiErrorResponse.detail = this.detail;
            apiErrorResponse.message = this.message;
            return apiErrorResponse;
        }
    }
}

ApiErrorResponse类中每个字段的含义等同于前面JSON格式的错误信息含义。 下面我们看看几种常见的客户端请求错误场景下如何使用这个ApiErrorResponse类: (1)当方法参数不是预期类型时,抛出MethodArgumentTypeMismatchException异常,我们构造ApiErrorResponse类嵌入ResponseEntity返回:

代码语言:javascript
复制
@ExceptionHandler({MethodArgumentTypeMismatchException.class})
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request){

     ApiErrorResponse response =new ApiErrorResponse.ApiErrorResponseBuilder()
        .withStatus(status)
        .withError_code(status.BAD_REQUEST.name())
        .withMessage(ex.getLocalizedMessage()).build();

        return new ResponseEntity<>(response, response.getStatus());
    }

(2),当API无法读取HTTP消息时,抛出HttpMessageNotReadable异常

代码语言:javascript
复制
@ExceptionHandler({HttpMessageNotReadableException.class})
    protected ResponseEntity<Object> handleHttpMessageNotReadable(HttpMessageNotReadableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        String error = "Malformed JSON request ";
        ApiErrorResponse response = new ApiErrorResponse.ApiErrorResponseBuilder()
                .withStatus(status)
                .withError_code("BAD_DATA")
                .withMessage(ex.getLocalizedMessage())
                .withDetail(error + ex.getMessage()).build();
        return new ResponseEntity<>(response, response.getStatus());
    }

下面是我们可以看到REST调用的响应JSON:

代码语言:javascript
复制
{
"status": "BAD_REQUEST",
"error_code": "BAD_DATA",
"message": "JSON parse error: Unexpected character 
"detail": "Malformed JSON request JSON parse error: Unexpected character ('<' (code 60)): expected a valid value (number, String, array, object, 'true', 'false' or 'null');
}

(3)处理自定义异常,将自定义异常返回给客户端API。 看一个简单的用例,当客户端API通过其唯一ID调用后端存储库查找记录时,如果找不到该记录,我们的存储库类会返回null或空对象,在这种情况下,即使找不到我们想要的资源记录,API也会向客户端返回http 200 (OK响应。 为了处理所有类似这样的情况,我们创建了一个自定义异常,并在全局异常处理器GlobalRestExceptionHandler中实现。

代码语言:javascript
复制
@ExceptionHandler(CustomServiceException.class)
protected ResponseEntity<Object> handleCustomAPIException(HttpMessageNotReadableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {

   ApiErrorResponse response =new ApiErrorResponse.ApiErrorResponseBuilder()
         .withStatus(status)
         .withError_code(HttpStatus.NOT_FOUND.name())
         .withMessage(ex.getLocalizedMessage())
         .withDetail(ex.getMessage())
         .build();
        return new ResponseEntity<>(response, response.getStatus());
 }

这里不会详细介绍如何在REST API中处理一个个不同的异常,因为所有异常都可以按照上面方式进行类似方式处理。下面是REST API中一些常见异常的类可以提供参考: HttpMediaTypeNotSupportedException HttpRequestMethodNotSupportedException TypeMismatchException (4)默认异常处理程序 既然我们无法处理系统中的所有异常。那么我们可以创建一个fallback异常处理器来作为没有指定异常处理器的默认异常处理器。

代码语言:javascript
复制
@ControllerAdvice
public class GlobalRestExceptionHandler extends ResponseEntityExceptionHandler {

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(Exception.class)
    public void defaultExceptionHandler() {
        // Nothing to do
    }
}

Spring Boot REST异常处理 Spring Boot提供了许多构建RESTful API的功能。Spring Boot 1.4引入了@RestControllerAdvice注释,这样可以更容易地处理异常。它和用@ControllerAdvice和@ResponseBody一样方便:

代码语言:javascript
复制
@RestControllerAdvice
public class RestExceptionHandler {

@ExceptionHandler(CustomNotFoundException.class)
public ApiErrorResponse handleNotFoundException(CustomNotFoundException ex) {

ApiErrorResponse response =new ApiErrorResponse.ApiErrorResponseBuilder()
      .withStatus(HttpStatus.NOT_FOUND)
      .withError_code("NOT_FOUND")
      .withMessage(ex.getLocalizedMessage()).build();

    return responseMsg;
    }
}

使用上述方法时,同时在Spring Boot的application.properties文件中将以下属性设置为true

spring.mvc.throw-exception-if-no-handler-found=true 如果处理一个请求发生异常没有异常处理器时,决定"NoHandlerFoundException"是否抛出

概要 在Spring基础REST API中正确处理和处理异常非常重要。在这篇文章中,我们介绍了实现Spring REST异常处理的不同选项。 为REST API构建一个良好的异常处理工作流是一个迭代和复杂的过程。一个好的异常处理机制允许API客户端知道请求出了什么问题。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-08-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Linyb极客之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • RESTful API中的异常Exception处理有两个基本要求,需要明确业务意义的错误消息以及hhtp状态码。良好的错误消息能够让API客户端纠正问题。在本文中,我们将讨论并实现Spring的REST API异常处理。 Restful API错误/异常设计 在RESTful API中设计异常处理时,最好在响应中设置HTTP状态代码,这样可以表示客户端的请求为什么会失败的原因。当然也可以发送更多信息包括HTTP状态码,这些将帮助客户端迅速定位错误。 比如下面是Springboot表示/api/producer不支持post方式的错误信息:
  • 对于我们的业务应用,应该提供更详细的有关业务的错误信息
  • 在设计REST API的响应时,需要理解以下重点: 1. status表示HTTP状态代码。 2. error_code表示REST API特定的错误代码。此字段有助于传递API /业务领域中特定信息。比如类似Oracle错误ORA-12345 3. message字段表示人类可读的错误消息。国际化信息 4. details部分表示完整详细信息。 5. information_link字段指定有关错误或异常的详细信息的链接。 Spring REST错误处理 Spring和Spring Boot提供了许多错误/异常处理选项。比如 @ExceptionHandler注释,@ExceptionHandler是一个Spring注释,以处理请求引发的异常。此注释在@Controller级别上起作用。
  • 该方法存在几个个问题或缺点: (1)此注释仅对指定的控制器Controller有效。 (2)这个注释不是全局的,我们需要添加到每个控制器(不是很方便)。 大多数企业应用程序都是需要扩展Spring基类的控制器(也就是通用控制器)。我们可以将@ExceptionHandler加入基类控制器,来克服上面的不便和限制,但是有以下新问题: (1)基类控制器不适用于所有类型的控制器。我们还是需要复制代码。 (2)程序员编写的控制器可能扩展不受我们控制的第三方面控制器类。 由于存在所有这些限制,因此建议不要在构建RESTful API时使用此方法 Spring的异常处理 Spring 3.2引入了@ControllerAdvice这个支持全局异常处理程序机制的注释。@ControllerAdvice可以让我们使用和上面完全相同的异常处理技术,但它是应用于整个应用程序,而不仅仅是某个控制器。看看下面的应用代码:
  • 通过@ControllerAdvice和@ExceptionHandler组合,能够统一跨所有@RequestMapping方法实现集中式异常处理。这是在使用基于Spring的REST API时的一种便捷方式,因为可以指定ResponseEntity为返回值。 现在我们可以定义一下我们的错误类信息的代码,然后把这个对象嵌入ResponseEntity中返回。
  • ApiErrorResponse类中每个字段的含义等同于前面JSON格式的错误信息含义。 下面我们看看几种常见的客户端请求错误场景下如何使用这个ApiErrorResponse类: (1)当方法参数不是预期类型时,抛出MethodArgumentTypeMismatchException异常,我们构造ApiErrorResponse类嵌入ResponseEntity返回:
  • (2),当API无法读取HTTP消息时,抛出HttpMessageNotReadable异常
  • 下面是我们可以看到REST调用的响应JSON:
  • (3)处理自定义异常,将自定义异常返回给客户端API。 看一个简单的用例,当客户端API通过其唯一ID调用后端存储库查找记录时,如果找不到该记录,我们的存储库类会返回null或空对象,在这种情况下,即使找不到我们想要的资源记录,API也会向客户端返回http 200 (OK响应。 为了处理所有类似这样的情况,我们创建了一个自定义异常,并在全局异常处理器GlobalRestExceptionHandler中实现。
  • 这里不会详细介绍如何在REST API中处理一个个不同的异常,因为所有异常都可以按照上面方式进行类似方式处理。下面是REST API中一些常见异常的类可以提供参考: HttpMediaTypeNotSupportedException HttpRequestMethodNotSupportedException TypeMismatchException (4)默认异常处理程序 既然我们无法处理系统中的所有异常。那么我们可以创建一个fallback异常处理器来作为没有指定异常处理器的默认异常处理器。
  • Spring Boot REST异常处理 Spring Boot提供了许多构建RESTful API的功能。Spring Boot 1.4引入了@RestControllerAdvice注释,这样可以更容易地处理异常。它和用@ControllerAdvice和@ResponseBody一样方便:
  • 使用上述方法时,同时在Spring Boot的application.properties文件中将以下属性设置为true
  • 概要 在Spring基础REST API中正确处理和处理异常非常重要。在这篇文章中,我们介绍了实现Spring REST异常处理的不同选项。 为REST API构建一个良好的异常处理工作流是一个迭代和复杂的过程。一个好的异常处理机制允许API客户端知道请求出了什么问题。
相关产品与服务
Serverless HTTP 服务
Serverless HTTP 服务基于腾讯云 API 网关 和 Web Cloud Function(以下简称“Web Function”)建站云函数(云函数的一种类型)的产品能力,可以支持各种类型的 HTTP 服务开发,实现了 Serverless 与 Web 服务最优雅的结合。用户可以快速构建 Web 原生框架,把本地的 Express、Koa、Nextjs、Nuxtjs 等框架项目快速迁移到云端,同时也支持 Wordpress、Discuz Q 等现有应用模版一键快速创建。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档