You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring MVC如何记录所有请求(含resource not found请求)

你说得太对了!Spring MVC的Interceptor确实搞不定那些「找不到资源」的404请求——毕竟Interceptor的执行逻辑是绑定在DispatcherServlet找到对应的handler之后的,连handler都找不到,Interceptor的前置、后置方法根本没机会触发。下面给你几个经过实践验证的可行方案:

解决方案1:自定义Servlet Filter(最通用的方式)

Filter是Servlet规范里的核心组件,它的执行时机早于Spring MVC的DispatcherServlet,不管请求最终能不能找到对应的handler,都会经过Filter,所以用它来统一记录所有请求非常靠谱。

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.time.LocalDateTime;

@WebFilter(urlPatterns = "/*")
public class RequestLoggingFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        // 记录请求核心信息
        String method = httpRequest.getMethod();
        String requestURI = httpRequest.getRequestURI();
        String remoteAddr = httpRequest.getRemoteAddr();
        LocalDateTime timestamp = LocalDateTime.now();

        System.out.printf("[%s] 请求信息:%s %s,来自IP:%s%n", timestamp, method, requestURI, remoteAddr);

        // 继续执行请求链,让后续组件处理请求
        chain.doFilter(request, response);

        // 这里还能记录响应状态码,比如404、200等
        int status = ((javax.servlet.http.HttpServletResponse) response).getStatus();
        System.out.printf("[%s] 响应状态码:%d%n", timestamp, status);
    }

    // init和destroy方法按需实现,不需要额外逻辑的话可以留空
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {}

    @Override
    public void destroy() {}
}

如果是Spring Boot项目,记得在启动类上加上@ServletComponentScan注解,让Spring能扫描到这个自定义Filter。

解决方案2:捕获NoHandlerFoundException(Spring MVC通用)

默认情况下,DispatcherServlet遇到找不到handler的请求时,不会抛出异常,而是直接返回404页面。我们需要先开启「找不到handler就抛异常」的配置,再通过全局异常处理器捕获并记录请求:

  1. 配置DispatcherServlet:

    • 若用XML配置(web.xml):
      <servlet>
          <servlet-name>dispatcher</servlet-name>
          <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
          <init-param>
              <param-name>throwExceptionIfNoHandlerFound</param-name>
              <param-value>true</param-value>
          </init-param>
          <load-on-startup>1</load-on-startup>
      </servlet>
      
    • 若用Java配置(Spring Boot):
      import org.springframework.boot.web.servlet.ServletRegistrationBean;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.web.servlet.DispatcherServlet;
      
      @Configuration
      public class WebConfig {
      
          @Bean
          public ServletRegistrationBean<DispatcherServlet> dispatcherServletRegistration(DispatcherServlet dispatcherServlet) {
              ServletRegistrationBean<DispatcherServlet> registration = new ServletRegistrationBean<>(dispatcherServlet);
              registration.addInitParameter("throwExceptionIfNoHandlerFound", "true");
              return registration;
          }
      }
      
  2. 自定义全局异常处理器捕获NoHandlerFoundException:

    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.servlet.NoHandlerFoundException;
    
    import javax.servlet.http.HttpServletRequest;
    import java.time.LocalDateTime;
    
    @ControllerAdvice
    public class GlobalExceptionHandler {
    
        @ExceptionHandler(NoHandlerFoundException.class)
        public String handleNoHandlerFound(NoHandlerFoundException ex, HttpServletRequest request) {
            // 记录404请求的详细信息
            String method = request.getMethod();
            String requestURI = request.getRequestURI();
            String remoteAddr = request.getRemoteAddr();
            LocalDateTime timestamp = LocalDateTime.now();
    
            System.out.printf("[%s] 404 Not Found:%s %s,来自IP:%s%n", timestamp, method, requestURI, remoteAddr);
    
            // 返回自定义404页面或JSON响应,根据你的业务需求调整
            return "error/404";
        }
    }
    
解决方案3:自定义ErrorController(Spring Boot专属)

Spring Boot默认提供了BasicErrorController来处理所有错误请求,我们可以自定义一个ErrorController来接管错误处理逻辑,同时记录请求信息:

import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;

@RestController
@RequestMapping("/error")
public class CustomErrorController implements ErrorController {

    @GetMapping
    public String handleError(HttpServletRequest request) {
        // 从请求属性中获取错误相关信息
        String method = request.getMethod();
        String requestURI = (String) request.getAttribute("javax.servlet.error.request_uri");
        String remoteAddr = request.getRemoteAddr();
        Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
        LocalDateTime timestamp = LocalDateTime.now();

        System.out.printf("[%s] 错误状态:%d,请求信息:%s %s,来自IP:%s%n", timestamp, statusCode, method, requestURI, remoteAddr);

        // 返回自定义错误响应,支持页面或JSON格式
        return String.format("请求出错啦:状态码 %d,路径 %s", statusCode, requestURI);
    }
}

内容的提问来源于stack exchange,提问作者Anurag Sharma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 07:47:25