java - Spring Boot 自定义 ErrorAttributes http 状态未设置为响应

标签 java spring rest spring-mvc spring-boot

跟随 Spring Boot documentation我定义了我自己的 ErrorAttributes bean(见下文),我能够使 json 响应显示我想要的信息,包括我自己的错误代码和消息,方法是使用自定义异常来包装该信息并从中生成错误响应。唯一的问题是响应的 http 状态与我在 status 属性中定义的状态不匹配,它没有被覆盖。

@Bean
public ErrorAttributes errorAttributes() {
    return new DefaultErrorAttributes() {
        @Override
        public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) {

            Map<String, Object> errorAttributes = super.getErrorAttributes(requestAttributes, includeStackTrace);

            Throwable error = getError(requestAttributes);

            if (error instanceof MyException) {
                MyException myException = (MyException) error;

                errorAttributes.put("errorCode", myException.getErrorCode());
                errorAttributes.put("message", myException.getMessage());
                errorAttributes.put("status", myException.getStatus());

                HttpStatus correspondentStatus = HttpStatus.valueOf(myException.getStatus());
                errorAttributes.put("error", correspondentStatus.getReasonPhrase());
            }

            return errorAttributes;
        }
    };
}

响应的http状态与json中的状态不匹配,例如:

HTTP/1.1 500 
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Wed, 01 Mar 2017 18:48:22 GMT
{
   "timestamp": "2017-03-01T18:48:21.894+0000",
   "status": 403,
   "error": "Forbidden",
   "exception": "com.myapp.MyException",
   "message": "You are not authorized. This user doesn't exist in the db",
   "path": "/account",
   "errorCode": "00013"
}

最佳答案

我找到了一种从创建我的自定义 ErrorAttributes bean 的逻辑中设置 http 状态的方法,这样我就可以重新使用开箱即用的 Spring Boot 错误响应创建并使用我的自定义信息更新它而无需需要异常处理程序和 Controller 建议。

通过添加下一行,您可以设置覆盖 requestAttributes 中当前状态的 http 状态。

requestAttributes.setAttribute("javax.servlet.error.status_code", httpStatus, 0);

其中 httpStatus 是您要设置的状态。

这是添加了一行的完整 bean 定义:

@Bean
public ErrorAttributes errorAttributes() {
    return new DefaultErrorAttributes() {
        @Override
        public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) {

            Map<String, Object> errorAttributes = super.getErrorAttributes(requestAttributes, includeStackTrace);

            Throwable error = getError(requestAttributes);

            if (error instanceof MyException) {
                MyException myException = (MyException) error;
                int httpStatus = myException.getStatus();

                errorAttributes.put("errorCode", myException.getErrorCode());
                errorAttributes.put("message", myException.getMessage());
                errorAttributes.put("status", httpStatus);

                HttpStatus correspondentStatus = HttpStatus.valueOf(httpStatus);
                errorAttributes.put("error", correspondentStatus.getReasonPhrase());
                requestAttributes.setAttribute("javax.servlet.error.status_code", httpStatus, 0);
            }

            return errorAttributes;
        }
    };
}

我是怎么找到它的?通过查看 DefaultErrorAttributes 类,我发现有一个方法 addStatus 是私有(private)的,但它显示了代码用来生成响应的 http-status 的属性的名称,这就是我正在寻找的线索:

private void addStatus(Map<String, Object> errorAttributes, RequestAttributes requestAttributes) {
    Integer status = (Integer)this.getAttribute(requestAttributes, "javax.servlet.error.status_code");
...

仔细查看代码,我发现那里正在调用的 getAttribute 方法实际上是从 RequestAttributes 接口(interface)调用该方法:

private <T> T getAttribute(RequestAttributes requestAttributes, String name) {
    return requestAttributes.getAttribute(name, 0);
}

检查该接口(interface)内部我发现还有一个 setAttribute 方法。它奏效了。

HTTP/1.1 403 
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Wed, 01 Mar 2017 20:59:33 GMT
{
   "timestamp": "2017-03-01T20:59:32.774+0000",
   "status": 403,
   "error": "Forbidden",
   "exception": "com.myapp.MyException",
   "message": "You are not authorized. This user doesn't exist in the db",
   "path": "/account",
   "errorCode": "00013"
}

关于java - Spring Boot 自定义 ErrorAttributes http 状态未设置为响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42541520/

相关文章:

java - 如何使用 session 工厂从 Java Hibernate 执行 sql 存储过程?

java - Spring Boot Rest API - 输入文件+端点

java - Android/Ormlite - 更新现有的或插入(如果不存在)

java - 如何在 Spring 中通过默认限定符 bean 名称获取 @Service bean

java - Spring Integration EnableIntegrationManagement 加上 MetricRegistry

java - Facebook access_token 检索

wordpress - 在 Wordpress.com 上使用 REST API 发帖 [错误 401,不允许]

java - 客户端休息 SSL java : javax.net.ssl.SSLHandshakeException

java - 图片和文字在同一个窗口

java - Iterator.class 与 Iterator<String>.class