弹簧启动自定义 http 错误响应?

2022-09-02 03:16:12

如果 Spring Boot Web 应用程序中发生异常,如何自定义响应状态代码和响应正文中的数据?

我创建了一个Web应用程序,如果由于某些不良的内部状态而发生意外情况,则会引发自定义异常。因此,触发错误的请求的响应正文如下所示:

HTTP/1.1 500 Internal Server Error
{
    "timestamp": 1412685688268,
    "status": 500,
    "error": "Internal Server Error",
    "exception": "com.example.CustomException",
    "message": null,
    "path": "/example"
}

现在,我想更改状态代码并在响应正文中设置字段。我脑海中闪过的一个解决方案是这样的:

@ControllerAdvice
class CustomResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    ErrorMessage handleBadCredentials(CustomException e) {
        return new ErrorMessage("Bad things happened");
    }
}

@XmlRootElement
public class ErrorMessage(
    private String error;

    public ErrorMessage() {
    }

    public ErrorMessage(String error) {
        this.error = error;
    }

    public String getError() {
        return error;
    }

    public void setError(String error) {
        this.error = error;
    }
)

然而,这创造了(正如怀疑的那样)一个完全不同的反应:

HTTP/1.1 400 Bad Request
{
    "error": "Bad things happened"
}

答案 1

正如@zeroflagL提到的,Spring Boot在 中捏造了“标准”错误响应体。与您的需求类似,我想利用所有这些,但只需增加一个由我的一些例外提供的“类型”字段。org.springframework.boot.autoconfigure.web.DefaultErrorAttributes

我通过实现一个子类.Spring Boot自动拾取它并使用我的而不是默认值。ComponentDefaultErrorAttributes

@Component
public class ExtendedErrorAttributes extends DefaultErrorAttributes {
    @Override
    public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, 
                                                  boolean includeStackTrace) {
        final Map<String, Object> errorAttributes = 
            super.getErrorAttributes(requestAttributes, 
                                     includeStackTrace);

        final Throwable error = super.getError(requestAttributes);
        if (error instanceof TypeProvider) {
            final TypeProvider typeProvider = (TypeProvider) error;
            errorAttributes.put("type", typeProvider.getTypeIdentifier());
        }

        return errorAttributes;
    }
}

这样,我得到了一个增强的JSON响应正文,例如

{
  "timestamp": 1488058582764,
  "status": 429,
  "error": "Too Many Requests",
  "exception": "com.example.ExternalRateLimitException",
  "message": "DAILY_LIMIT: too many requests",
  "path": "/api/lookup",
  "type": "DAILY_LIMIT"
}

答案 2

http 响应状态代码可以通过使用 HttpServletResponse.sendError(int) 方法进行更改,例如

@ExceptionHandler
void handleIllegalArgumentException(IllegalArgumentException e, HttpServletResponse response) throws IOException {
    response.sendError(HttpStatus.BAD_REQUEST.value());
}

或者,如果您有两个或多个异常来生成相同的响应状态,则可以在注释中声明异常类型:@ExceptionHandler

@ExceptionHandler({IllegalArgumentException.class, NullPointerException.class})
void handleBadRequests(HttpServletResponse response) throws IOException {
    response.sendError(HttpStatus.BAD_REQUEST.value());
}

更多信息可以在我的博客文章中找到。


推荐