Spring Boot自定义http错误响应?

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

我创建了一个Web应用程序,如果由于某些错误的内部状态而发生意外情况,则会引发自定义exception。 因此,触发错误的请求的响应主体看起来像:

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" } 

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

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

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

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

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

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

我通过实现对DefaultErrorAttributes子分类的Component来实现这一点。 Spring Boot自动将其拾取并使用我的而不是默认值。

 @Component public class ExtendedErrorAttributes extends DefaultErrorAttributes { @Override public Map getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) { final Map 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" }