我有一个在嵌入式 Tomcat 上运行的 Spring Boot REST API。我使用
@ControllerAdvice
来自定义错误响应。在负面测试期间,我注意到,如果我故意发送格式错误的标头,我会在o.apache.coyote.http11.Http11Processor : Error parsing HTTP request header
中收到异常(如预期),但@ControllerAdvice
不会拾取它。
是否可以在 Spring Boot 应用程序中捕获这些异常?
在Spring Boot应用程序中,@ControllerAdvice用于在控制器中全局处理异常。不过,@ControllerAdvice 只能捕获 Spring MVC 处理链中的异常,而不能捕获 Tomcat 服务器解析 HTTP 请求头时发生的低级异常,例如解析 HTTP 请求头时出错。 要捕获这些异常,需要在较低级别进行处理,例如通过自定义 Tomcat 的 ErrorPage 或 ErrorPageFilter。以下是一个例子:
1.创建自定义ErrorPageFilter
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.web.filter.ErrorPageFilter;
import org.springframework.web.filter.GenericFilterBean;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Configuration
public class CustomErrorPageConfig {
@Bean
public FilterRegistrationBean<GenericFilterBean> errorPageFilter() {
FilterRegistrationBean<GenericFilterBean> registration = new FilterRegistrationBean<>();
registration.setFilter(new CustomErrorPageFilter());
registration.addUrlPatterns("/*");
registration.setOrder(1);
return registration;
}
public static class CustomErrorPageFilter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
try {
chain.doFilter(request, response);
} catch (IOException | ServletException e) {
handleException((HttpServletRequest) request, (HttpServletResponse) response, e);
}
}
private void handleException(HttpServletRequest request, HttpServletResponse response, Exception e) {
response.setStatus(HttpStatus.BAD_REQUEST.value());
response.setContentType("application/json");
response.getWriter().write("{\"error\": \"Invalid request header\"}");
response.getWriter().flush();
}
}
}
2.配置错误页面
import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.server.ErrorPageRegistrar;
import org.springframework.boot.web.server.ErrorPageRegistry;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
@Configuration
public class ErrorPageConfig implements ErrorPageRegistrar {
@Override
public void registerErrorPages(ErrorPageRegistry registry) {
ErrorPage error400Page = new ErrorPage(HttpStatus.BAD_REQUEST, "/error");
registry.addErrorPages(error400Page);
}
}
3.创建错误处理控制器
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ErrorController {
@RequestMapping("/error")
public ResponseEntity<String> handleError() {
return new ResponseEntity<>("Invalid request header", HttpStatus.BAD_REQUEST);
}
}