【问题标题】:How to change Status code in spring boot error response?如何更改 Spring Boot 错误响应中的状态码?
【发布时间】:2019-07-01 18:05:46
【问题描述】:

我正在制作一个简单的休息服务,它会进行一些 http 调用并使用 RestTemplate 聚合数据。

有时我会收到 NotFound 错误,有时会收到 BadRequest 错误。

我想用相同的状态代码响应我的客户,而 Spring 似乎有这个开箱即用的映射。消息正常,但状态码始终为 500 Internal Server error。

我想将我的状态码映射到我最初收到的状态码

    "timestamp": "2019-07-01T17:56:04.539+0000",
    "status": 500,
    "error": "Internal Server Error",
    "message": "400 Bad Request",
    "path": "/8b8a38a9-a290-4560-84f6-3d4466e8d7901"
}

我希望是这样的

    "timestamp": "2019-07-01T17:56:04.539+0000",
    "status": 400,
    "error": "Internal Server Error",
    "message": "400 Bad Request",
    "path": "/8b8a38a9-a290-4560-84f6-3d4466e8d7901"
}

它抛出 HttpClientErrorException.BadRequest 或 HttpClientErrorException.NotFound

我的代码是一个简单的端点:

    @GetMapping("/{id}")
    public MyModel getInfo(@PathVariable String id){
        return MyService.getInfo(id);
    }

【问题讨论】:

    标签: java spring rest spring-boot controller


    【解决方案1】:

    您可以使用@ControllerAdvice 注释创建全局异常处理。像这样:

    @ControllerAdvice
    public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
    
        @ExceptionHandler(value = YourExceptionTypes.class)
        protected ResponseEntity<Object> handleBusinessException(RuntimeException exception, WebRequest request) {
            return handleExceptionInternal(exception, exception.getMessage(), new HttpHeaders(), HttpStatus.NOT_ACCEPTABLE, request);
        }
    }
    

    当抛出异常时,处理程序将捕获并将其转换为所需的响应。原始异常不会被传播。

    【讨论】:

    • 谢谢,这段代码应该在我的项目中的什么位置?在单独的类中还是在我的控制器类中?
    • 在单独的类中
    • 这实际上不能按要求工作。通过使用@ControllerAdvice,必须手动构建整个主体并将其转换为 JSON。代码 sn -p 中的整个响应体将是异常的消息——“handelExceptionInternal”的第二个参数。该正文不是 JSON,所有其他信息都丢失了,它只是一个带有消息的字符串。所以这不是一个适当的解决方案。
    • 如果你想要常见的错误格式,你可以创建自己的pojo来返回你需要的正确信息。对象会被objectmapper自动序列化。
    【解决方案2】:

    @ControllerAdvice 接受的解决方案是不够的。这肯定会使用异常的自定义状态代码标记响应。但是,它不会将所需的响应正文作为 JSON 返回,而只是作为简单的字符串 - 来自异常的消息。

    要获得正确的状态代码和默认错误正文,DefaultErrorAttributes 可以提供帮助。

    @ControllerAdvice
    public class PackedTemplateNotRecodableExceptionControllerAdvice extends ResponseEntityExceptionHandler {
        @Autowired
        private DefaultErrorAttributes defaultErrorAttributes;
    
        @ExceptionHandler(PackedTemplateNotRecodableException.class)
        public ResponseEntity<Object> handlePackedTemplateNotRecodableException(final RuntimeException exception, final WebRequest webRequest) {
            // build the default error response
            webRequest.setAttribute(RequestDispatcher.ERROR_STATUS_CODE, HttpStatus.BAD_REQUEST.value(), RequestAttributes.SCOPE_REQUEST);
            final Map<String, Object> errorAttributes = defaultErrorAttributes.getErrorAttributes(webRequest, ErrorAttributeOptions.defaults());
    
            // return the error response with the specific response code
            return handleExceptionInternal(exception, errorAttributes, new HttpHeaders(), HttpStatus.BAD_REQUEST, webRequest);
        }
    }
    

    这样您将收到所需的错误响应,例如像这样:

    {
        "timestamp": "2019-07-01T17:56:04.539+0000",
        "status": 400,
        "error": "Internal Server Error",
        "message": "400 Bad Request",
        "path": "/8b8a38a9-a290-4560-84f6-3d4466e8d7901"
    }
    

    【讨论】:

    • 请注意:ErrorAttributeOptions.defaults() 无法编译。相反,我们可以使用 getErrorAttributes(WebRequest webRequest, boolean includeStackTrace)
    【解决方案3】:

    我花了很多时间研究这个问题,包括这里的答案中的解决方案,这对我不起作用(或者我没有正确实施)。

    我终于有了突破。我没有抛出诸如throw new Exception(message) 之类的通用异常,而是为特定异常类型创建了扩展Exception 类的类 - 以及它们各自的 HTTP 错误代码和消息

    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    public class BadRequestException extends Exception{
    
        public BadRequestException(String message) {
           super(message);
        }
    }
    

    在您的应用程序逻辑中,您现在可以使用类似throw new BadRequestException("Invalid Email") 的消息抛出错误请求异常。这将导致抛出异常:

    {
    "timestamp": "2021-03-01T17:56:04.539+0000",
    "status": 400,
    "error": "Bad Request",
    "message": "Invalid Email",
    "path": "path to controller"
    }
    

    您现在可以为您想要的不同异常创建其他自定义异常类,按照上面的示例并更改 @ResponseStatus 中的 value 参数,以匹配您想要的所需响应代码。例如,对于 NOT FOUND 异常 @ResponseStatus (value = HttpStatus.NOT_FOUND),Java 通过 HttpStatus 枚举提供不同的 HTTP 状态代码。

    For more context

    我希望这足够详细并且可以帮助某人:)

    【讨论】:

      【解决方案4】:

      Spring Resttemplate exception handling 的可能重复项 您的代码需要一个控制器建议来处理来自它所调用的服务的异常。

      【讨论】:

        猜你喜欢
        • 2018-02-05
        • 2021-12-14
        • 2013-01-16
        • 2020-08-12
        • 2023-02-17
        • 2017-08-23
        • 2018-03-18
        • 2021-05-30
        • 1970-01-01
        相关资源
        最近更新 更多