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