0

我制作了这个简单的 Spring Boot 应用示例来展示我在 Spring Boot 默认处理错误的方式方面的问题:

package com.pany.app;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MyApplication {

    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }

}

这是 Spring Security 配置:

package com.pany.app;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {

    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/**").anonymous();
    }

}

这是 REST 控制器:

package com.pany.app;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.HttpClientErrorException;

@RestController
public class MyController {

    @GetMapping(path = "/", produces = { "application/json" })
    public void home() {
        throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, "This is my custom 400 Bad Request message");
    }

}

现在,Spring Boot 2.1.8.RELEASE当调用 URL 时,http://localhost:8080/我得到一个带有 500 代码的 HTTP 响应和以下 JSON 响应:

{
  "timestamp": "2020-09-14T07:24:22.061+0000",
  "status": 500,
  "error": "Internal Server Error",
  "message": "400 This is my custom 400 Bad Request message",
  "path": "/"
}

然而,HTTP 状态代码与预期不同(500 而不是 400),以及 JSON 中的各种字段(“状态”、“错误”、“消息”,前面有意外的“代码”)。

我也用Spring Boot 2.3.3.RELEASE...测试了这个,现在它甚至不再像以前那样工作了!!

{
  "timestamp": "2020-09-14T07:34:23.154+00:00",
  "status": 500,
  "error": "Internal Server Error",
  "message": "",
  "path": "/"
}

所有这些都是通过诸如 和 的类/接口来处理ErrorControllerAbstractErrorControllerBasicErrorController全部设置在 中ErrorMvcAutoConfiguration)。显然有一个重定向到 URL/error的原始请求/和/或响应包装到其他东西中,例如我可以调试我的请求,如下所示:SecurityContextHolderAwareRequestWrapper[FirewalledRequest[org.apache.catalina.core.ApplicationHttpRequest@3751bea4]]

我发现我得到的 JSON 是通过一个名为的 bean 生成的,该 beanDefaultErrorAttributes从 key 下的请求中提取 HTTP 状态代码"javax.servlet.error.status_code"

我在那里读到:https ://github.com/spring-projects/spring-boot/issues/4694#issuecomment-163597864 (2015年12月):

问题实际上出在 BasicErrorController 中,并且特定于 HTML 响应。BasicErrorController.error 使用 ErrorPageFilter 设置的 javax.servlet.error.status_code 属性设置响应状态,但 BasicErrorController.errorHtml 没有。这导致 text/html 错误响应的状态为 200 OK。

事实上,就我而言,ErrorPageFilter从未调用过。

在 Spring Boot 项目上还发现了另一个问题:https ://github.com/spring-projects/spring-boot/issues/20412这与我的问题非常相关,但仍然没有提供解决方案。

回到我的控制器的设计方式(请记住,这只是一个极其简化的示例):如何“自定义”Spring Boot 以获得带有代码 400 的 HTTP 响应和此 JSON 作为响应:

{
  "timestamp": "2020-09-14T07:24:22.061+0000",
  "status": 400,
  "error": "Bad Request",
  "message": "This is my custom 400 Bad Request message",
  "path": "/"
}

谢谢。

4

2 回答 2

1

进行自定义错误响应的最简单方法是添加一个 Controller Advice 类,该类将捕获和处理异常。

@ControllerAdvice
public class ControllerAdvice {
    @ResponseBody
    @ExceptionHandler(value = HttpClientErrorException.class) {
    public ResponseEntity<ExceptionResponseBody> genericException(HttpClientErrorException exception) {
        // Build and return your response

您可以从异常中获取代码和消息以构建响应。您可以添加更多处理程序来捕获和处理您想要的所有错误。

于 2020-09-14T08:30:49.290 回答
1

一个简单的替代方法@Controlleradvice是自定义异常如下

@Slf4j
@ResponseStatus(HttpStatus.NOT_FOUND)
public class NotFoundException extends RuntimeException{

  public NotFoundException(String message) {
    super(message);
    log.warn(message);
  }

}

@ResponseStatus使用带有注释的所需 Http 代码。

并在需要时抛出此异常

throw new NotFoundException("Your message for not found goes here");
于 2020-09-14T11:06:03.670 回答