首页 > 解决方案 > 使用约束注释时如何使用spring boot返回http错误响应

问题描述

我正在使用 React 和 Spring-boot 开发一个项目。到目前为止,我已经成功创建了一个注册页面,将用户(用户名、密码、电子邮件)插入到从 spring boot 管理的 postgres 数据库中。但是,现在我想在后端过滤这个输入,这样我就不会收到不需要的用户名、密码、电子邮件。

经过一些谷歌搜索后,我发现我可以使用@Pattern 和@Size 等注释约束来做到这一点。使用注释目前似乎满足了我的需求。如果有更好的方法,请随时提出更好的方法。

我的问题是如何将唯一的 http 错误消息返回到反应前端。在我看来,每个注释都应该有自己的错误 ID。例如,

@Column(name = "password")
@Pattern(regexp = "[^\s]*", message = "Password should not contain whitespaces")
@Size(min = 8, max = 16, message = "Password should be between 8 and 16 characters")
private String userPassword;

为了在前端通知客户端,我需要以某种方式获取错误 ID 或消息。

使用邮递员发送一些无效输入我收到 400 条错误消息,但返回的 JSON 太复杂了。我不需要太多信息,只需要源错误。

奇怪的是,使用唯一的真实约束

@Column(name = "email", unique = true)
private String userEmail;

给我一个 500 状态错误,而且描述错误的 json 与 400 完全不同。

我只是想用描述错误的简单 json 结构返回 40x 错误。理想情况下,我想处理由注释引起的异常,或者因为我在函数内手动抛出异常。

标签: javaspringspring-bootannotations

解决方案


您需要其中之一:

@RestControllerAdvice
@Slf4j
public class ExceptionHandler {

  // this catches everything that you don't handle specifically.
  @ExceptionHandler({Exception.class})
  @ResponseStatus(INTERNAL_SERVER_ERROR)
  public ErrorMessage handleException(Exception e) {
    log.warn("An unexpected error occurred", e);
    return ErrorMessage
      .builder()
      .cause("Internal server error")
      .detail(e.getMessage())
      .build();
  }

  @ResponseStatus(BAD_REQUEST)
  @ExceptionHandler(ConstraintViolationException.class)
  public ErrorMessage handleConstraintViolationException(ConstraintViolationException e) {

    log.info(e.getMessage());

    List<FieldError> fieldErrors = e.getConstraintViolations()
        .stream()
        .map(violation -> FieldError
            .builder()
            .description(violation.getMessage())
            .field(violation.getPropertyPath().toString())
            .rejectedValue(violation.getInvalidValue())
            .build())
        .collect(Collectors.toList());

    return ErrorMessage
        .builder()
        .cause("Constraint violation")
        .detail("The request was invalid.")
        .fieldErrors(fieldErrors)
        .build();
  }
}

您可以根据需要添加其他处理程序(NOT_FOUND、CONFLICT 等),也可以为其他类型的异常添加更多 BAD_REQUEST 处理程序(MethodArgumentNotValidException、MissingServletRequestParameterException、HttpMessageNotReadableException)。

仔细考虑您返回的错误的结构,因为它们构成您与客户的 API 合同的一部分,并且一旦发布到野外,在更改它们时需要非常小心。此外,在您的响应中使用异常消息时要小心,因为这可能会揭示您的实现细节 - 知道您使用过 Java 和 Spring Boot 可能会让攻击者踏上大门)。

至于唯一的错误代码,那是另一个有趣的世界。我建议让它们保持简单和通用。使用助记符而不是不直观的代码。例如 MandatoryField 比 ABC-00234 更容易理解。


推荐阅读