Spring Boot 自定义 http 错误响应?

Posted

技术标签:

【中文标题】Spring Boot 自定义 http 错误响应?【英文标题】:Spring Boot customize http error response? 【发布时间】:2014-12-01 22:15:44 【问题描述】:

如果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"

【问题讨论】:

@zeroflagL 最好,我想自定义 Spring Boot 生成的响应(如果可能的话)。实施一个完整的自定义解决方案(如问题中提供的解决方案)是可行的,但在不同项目之间的可重用性较差。 自定义解决方案是否可重用完全取决于您。 FWIW:resposne 主体由DefaultErrorAttributes#getErrorAttributes 组装。您可以将该类注入您的CustomResponseEntityExceptionHandler @zeroflagL 我未能让您的建议发挥作用(在我提交的issue 中向下滚动)。但是,我确实在寻找解决方案方面得到了帮助,请参阅下面的答案(或阅读我的 blog post)。 【参考方案1】:

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

我通过实现一个子类DefaultErrorAttributesComponent 来做到这一点。 Spring Boot 自动拾取并使用我的而不是默认的。

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

【讨论】:

很好的答案!如果您不想泄露这些细节,也可以轻松修改以从生产部署中的错误响应中删除“异常”属性。 到目前为止(可能从 Spring Boot 2 开始),您需要扩展 org.springframework.boot.web.servlet.error.DefaultErrorAttributes 具有 org.springframework.web.context.request.WebRequest在参数中而不是 RequestAttributes 中。 另外,由于 spring boot 2 getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) 已被弃用。使用getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions errorAttributeOptions)【参考方案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());

更多信息可以在我的blog post找到。

【讨论】:

值得注意的是,这里设置响应状态码;响应消息的其余部分保持不变。虽然这不是提问者所要求的,但这正是我自己的用例所需要的。

以上是关于Spring Boot 自定义 http 错误响应?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Spring Boot 中发送 400、401、405、403 和 500 错误的自定义响应?

由 CORS 阻止的 Spring Boot 自定义响应标头

Spring Boot 测试自定义错误控制器

Spring boot - 预检响应没有 HTTP ok 状态

如何在 Spring Boot Rest api 响应的 ResponseEntity 中添加自定义属性

抛出异常时,Spring Boot 不显示自定义错误