使用SpringBoot处理RESTAPI错误

导言

SpringBoot提供了一种开箱即用的异常处理机制。的默认实现。ErrorController在捕获和处理异常方面做得很好。而且,我们仍然可以定义我们自己的@ExceptionHandlerS来捕获和处理特定的异常。但是,仍有改进的余地:

即使我们决定使用自定义来处理所有异常@ExceptionHandler,某些异常仍将设法转义该处理程序和ErrorController将负责异常处理。这@ExceptionHandlerv.V.ErrorController二元性是绝对可以改善的。
有时,默认的错误表示看起来有点混乱:

{
  "timestamp": "2018-09-23T15:05:32.681+0000",
  "status": 400,
  "error": "Bad Request",
  "errors": [
    {
      "codes": [
        "NotBlank.dto.name",
        "NotBlank.name",
        "NotBlank.java.lang.String",
        "NotBlank"
      ],
      "arguments": [
        {
          "codes": [
            "dto.name",
            "name"
          ],
          "arguments": null,
          "defaultMessage": "name",
          "code": "name"
        }
      ],
      "defaultMessage": "{name.not_blank}",
      "objectName": "dto",
      "field": "name",
      "rejectedValue": null,
      "bindingFailure": false,
      "code": "NotBlank"
    }
  ],
  "message": "Validation failed for object='dto'. Error count: 1",
  "path": "/"
}

当然,我们可以通过注册一个自定义来改进这一点。ErrorAttributes实现,但更明智和固执己见(仍然很容易定制)的默认表示将是最好的。

对于验证错误,可以很容易地将约束中的一些参数公开给内插消息。例如,int值可以使用{}占位符语法但是,其他例外情况并非如此:

public class UserAlreadyExistsException extends RuntimeException {
    // How can I expose this value to the interpolated message?
    private final String username;
    // constructors and getters and setters
}

如果我们有内置的支持应用层错误码所有例外。有时,只需使用适当的http状态代码,我们找不到到底出了什么问题。例如,如果同一个端点上的两个完全不同的错误具有相同的状态代码,怎么办?

有待改进的余地

这个errors-spring-boot-starter提供一种Bootiful、一致和固执己见的方法来处理各种异常。基于SpringBoot的异常处理机制,errors-spring-boot-starter报盘:

1,处理所有异常的一致方法–不管是验证/绑定错误还是自定义域特定的错误,甚至是与Spring相关的错误。所有这些都将由WebErrorHandler实现处理(不再有ErrorController VS@ExceptionHandler)
2,对应用程序特定错误代码的内置支持,同样适用于所有可能的错误.
3,使用MessageSource的简单错误消息插值。
4,可自定义的HTTP错误表示形式。
5,公开从异常到错误消息的参数。

默认错误表示

默认情况下,错误将是具有以下模式的JSON结果:


// For each error, there is a code/messsge combination in the errors array
{
  "errors": [
    {
      "code": "first_error_code",
      "message": "1st error message"
    }
  ]
}

为了自定义此表示,只需注册HttpErrorAttributesAdapter。

一致错误处理方法

所有异常将由WebErrorHandler执行。默认情况下,这个启动程序会参考一些内置的内容。WebErrorHandler方法来处理下列特定异常:

1,处理所有验证/绑定异常的实现。
2,类注释的自定义异常的实现。@ExceptionMapping.
3,一个处理SpringMVC特定异常的实现。
4,如果SpringSecurity在类路径上,则是一个处理SpringSecurity特定异常的实现。
通过实现WebErrorHandler实现.

内置错误代码支持

虽然在RESTfulAPI中使用适当的HTTP状态代码是一种推荐的方法,但有时我们需要更多的信息来了解到底出了什么问题。这里是错误码进来。您可以将错误代码视为机器可读性错误描述。每个异常都可以映射到至少一个错误代码。

这个异常到错误代码映射根据异常类型而有所不同:

验证错误代码将从message 相应约束注释的属性,例如@NotBlank(message = “name.required”).
这个errorCode属性为带注释的异常。@ExceptionMapping如下所示:

@ExceptionMapping(statusCode = BAD_REQUEST, errorCode = "user.already_exists")
public class UserAlreadyExistsException extends RuntimeException {}

自定义实现的代码WebErrorHandler :

public class ExistedUserHandler implements WebErrorHandler {
    @Override
    public boolean canHandle(Throwable exception) {
        return exception instanceof UserAlreadyExistsException;
    }
    @Override
    public HandledException handle(Throwable exception) {   
        return new HandledException("user.already_exists", BAD_REQUEST, null);
    }
}

揭露论点

与SpringBoot一样,您可以从约束注释传递验证参数。@Min(value = 18, message = “age.min”),到拟内插信息:

age.min = The minimum age is {0}!

此外,为了支持验证错误的此特性,我们使用@ExposeAsArg 注释例如,如果我们要在以下消息中指定已经使用的用户名:

user.already_exists=Another user with the '{0}' username already exists

你可以写:


@ExceptionMapping(statusCode = BAD_REQUEST, errorCode = "user.already_exists")
public class UserAlreadyExistsException extends RuntimeException {
    @ExposeAsArg(0) private final String username;
    // constructor
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章