如何捕获Http11Processor抛出的HTTP请求头解析错误并记录请求IP
问题描述
- 运行环境:AWS EC2 实例 + Spring Boot(嵌入式Tomcat)+ Log4J2 日志框架
- 核心问题:正常请求的访问日志(含请求IP、端点、响应耗时)可通过自定义
Log4JAccessValve记录,但请求头/请求行解析失败时,Tomcat的Http11Processor抛出的错误日志默认不包含请求IP,且该异常不会经过AccessLogValve - 需求:捕获这类请求解析异常,记录发起请求的客户端IP,用于拦截恶意扫描机器人
解决方案
方法1:自定义Tomcat Error Valve(推荐)
Tomcat的ErrorReportValve负责处理请求生命周期中所有未被捕获的异常,包括Http11Processor阶段的请求解析错误。我们可以通过自定义该Valve来捕获异常并补充IP信息:
1. 实现自定义Error Valve
import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; import org.apache.catalina.valves.ErrorReportValve; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import javax.servlet.ServletException; import java.io.IOException; public class Log4JErrorValve extends ErrorReportValve { private static final Logger errorLog = LogManager.getLogger("http_error_log"); @Override protected void report(Request request, Response response, Throwable throwable) { // 获取客户端IP地址 String clientIp = request.getRemoteAddr(); // 记录包含IP的错误日志 errorLog.error("请求解析失败,客户端IP: {}", clientIp, throwable); // 可选:若不需要Tomcat默认的错误日志输出,可注释下方代码 super.report(request, response, throwable); } }
2. 在Spring Boot中注册自定义Valve
通过配置TomcatServletWebServerFactory将自定义Valve添加到Tomcat引擎:
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.server.WebServerFactoryCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class TomcatConfig { @Bean public WebServerFactoryCustomizer<TomcatServletWebServerFactory> tomcatCustomizer() { return factory -> { factory.addEngineValves(new Log4JErrorValve()); }; } }
方法2:扩展Http11Processor(进阶)
若需要更底层的控制,可通过扩展Http11Processor捕获解析异常,但该方式复杂度较高,仅推荐在特殊场景下使用:
1. 自定义Http11Processor
import org.apache.coyote.http11.Http11Processor; import org.apache.coyote.Request; import org.apache.coyote.Response; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.io.IOException; public class CustomHttp11Processor extends Http11Processor { private static final Logger errorLog = LogManager.getLogger("http_error_log"); public CustomHttp11Processor(org.apache.coyote.ProtocolHandler protocolHandler) { super(protocolHandler); } @Override public void service(Request request, Response response) throws IOException { try { super.service(request, response); } catch (IllegalArgumentException | IOException e) { // 获取客户端IP String clientIp = request.getRemoteAddr(); errorLog.error("请求解析失败,客户端IP: {}", clientIp, e); // 重新抛出异常,保证Tomcat后续错误处理流程正常执行 throw e; } } }
2. 注册自定义Processor
需自定义NioEndpoint替换默认处理器,再配置到Tomcat工厂中,代码相对繁琐,优先推荐方法1。
关键说明
AccessLogValve仅处理完成完整请求生命周期的请求,而请求解析失败发生在请求进入Servlet容器之前,因此不会触发该ValveErrorReportValve是Tomcat处理所有未捕获异常的入口,覆盖请求解析阶段的错误,因此能捕获Http11Processor抛出的异常- 记录IP后,可通过AWS WAF或自定义拦截器(如Spring的
HandlerInterceptor)实现恶意IP拦截
内容的提问来源于stack exchange,提问作者Maurice
相关产品推荐
相关产品推荐

