3

Spring Boot错误处理库包为REST API提供更好的错误处理 | foojay

 2 years ago
source link: https://www.jdon.com/57146
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Spring Boot错误处理库包为REST API提供更好的错误处理

好API 与坏API的区别是错误处理,Spring Boot 允许您自定义应用程序的错误处理,但是如果您想正确地执行此操作,则涉及很多低级编码。

构成良好的错误处理和良好的错误响应的最佳实践是什么?,这是可能有争议,但我认为我们可以就一些一般准则达成一致:

  • HTTP 响应代码应反映错误的性质(例如,对于未找到的内容返回 404,对于验证错误返回 400)
  • 响应正文应包含有关确切错误的更多信息。
  • 响应主体应该有一种代码,客户端可以在其中采取行动(例如USER_NOT_FOUND)
  • 对于验证问题,响应正文应指明字段名称,以便客户端可以例如突出显示存在验证问题的表单字段。

Spring Boot 的默认机制在这些方面做得并不好,因此Error Handling Spring Boot Starter库就派上用场了。

当您将库添加到 Spring Boot 应用程序时,它会自动注册一个控制器通知,该通知将为常见的 Spring 异常返回非常好的响应主体。

例如,这是针对@RestController方法的验证错误返回的内容:

{
  "code": "VALIDATION_FAILED",
  "message": "Validation failed for object='exampleRequestBody'. Error count: 2",
  "fieldErrors": [
    {
      "code": "INVALID_SIZE",
      "property": "name",
      "message": "size must be between 10 and 2147483647",
      "rejectedValue": ""
    },
    {
      "code": "REQUIRED_NOT_BLANK",
      "property": "favoriteMovie",
      "message": "must not be blank",
      "rejectedValue": null
    }
  ]
}

另一个例子是当ObjectOptimisticLockingFailureException发生时:

{
  "code": "OPTIMISTIC_LOCKING_ERROR",
  "message": "Object of class [com.example.user.User] with identifier [87518c6b-1ba7-4757-a5d9-46e84c539f43]: optimistic locking failed",
  "identifier": "87518c6b-1ba7-4757-a5d9-46e84c539f43",
  "persistentClassName": "com.example.user.User"
}
 

自定义应用程序异常

对于您在自己的应用程序中创建的 Exception 类,库将code使用 Exception 类的名称生成错误。例如,如果您有UserNotFoundException,USER_NOT_FOUND则会生成错误代码。

在代码中,对于这样的异常类:

@ResponseStatus(HttpStatus.NOT_FOUND)
public class UserNotFoundException extends RuntimeException {
    public UserNotFoundException(UserId userId) {
        super("Could not find user with id " + userId);
    }
}

将返回以下 JSON:

{
  "code": "USER_NOT_FOUND",
  "message": "Could not find user with id 123"
}

该库还遵循@ResponseStatus注释来确定所使用的 HTTP 响应代码。

可以通过以下几种方式自定义此基本行为:

  1. 通过覆盖错误代码 application.properties
  2. 通过覆盖错误代码 @ResponseErrorCode
  3. 在错误响应中添加额外的字段

通过属性覆盖错误代码

使用error.handling.codes异常类的键和全限定名,可以更改错误代码。例如:

error.handling.codes.com.company.app.user.UserNotFoundException=COULD_NOT_FIND_USER

应用它会将响应正文更改为如下所示:

{
  "code": "COULD_NOT_FIND_USER",
  "message": "Could not find user with id 123"
}

如果您不拥有 Exception 类型,这可能是影响错误代码的唯一方法。如果您确实拥有 Exception 类型,那么使用@ResponseErrorCode注释可能更容易。

通过注解覆盖错误代码

通过@ResponseErrorCode在类级别添加注释,我们可以覆盖使用的错误代码。

@ResponseStatus(HttpStatus.NOT_FOUND)
@ResponseErrorCode("NO_SUCH_USER")
public class UserNotFoundException extends RuntimeException {
    public UserNotFoundException(UserId userId) {
        super("Could not find user with id " + userId);
    }
}

将生成以下响应:

{
  "code": "NO_SUCH_USER",
  "message": "Could not find user with id 123"
}

在响应中的添加其他字段

如果您想在错误响应中添加其他字段,则可以通过在 Exception 类上使用@ErrorResponseProperty.

@ResponseStatus(HttpStatus.NOT_FOUND)
public class UserNotFoundException extends RuntimeException {

    private final UserId userId;

    public UserNotFoundException(UserId userId) {
        super(String.format("Could not find user with id %s", userId));
        this.userId = userId;
    }

    @ResponseErrorProperty
    public String getUserId() {
        return userId.getValue();
    }
}

将生成以下响应:

{
  "code": "USER_NOT_FOUND",
  "message": "Could not find user with id UserId{id=8c7fb13c-0924-47d4-821a-36f73558c898}",
  "userId": "8c7fb13c-0924-47d4-821a-36f73558c898"
}

请注意userId响应中的额外字段。

测试

使用该库的优势之一也是测试支持。确切的同样的错误响应使用实际应用时,或使用一个完整的集成测试用时返回@SpringBootTest,或者使用Web测试片的@WebMvcTest。

当使用MockMvc+Error Handling Spring Boot Starter时,你能使用MockMvc测试错误处理,无需启动一个完整的@SpringBootTest.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK