Springboot如何利用拦截器拦截请求信息收集到日志详解

  • Post category:http

下面我来为你详细讲解SpringBoot如何利用拦截器拦截请求信息并将其收集到日志中。具体步骤如下:

1. 创建 Interceptor 类

首先,我们需要创建一个拦截器,继承 HandlerInterceptorAdapter 类,并重写其中的方法,从而实现我们自己的业务逻辑。

public class RequestLogInterceptor extends HandlerInterceptorAdapter {

    private static final Logger logger = LoggerFactory.getLogger(RequestLogInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 记录请求信息
        logger.info("Request URL: {},Method: {}", request.getRequestURL(), request.getMethod());
        logger.info("Request IP: {}", request.getRemoteAddr());
        long startTime = System.currentTimeMillis();
        request.setAttribute("startTime", startTime);
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 记录响应信息
        long startTime = (long) request.getAttribute("startTime");
        long currentTime = System.currentTimeMillis();
        long duration = currentTime - startTime;
        logger.info("Response Status: {}", response.getStatus());
        logger.info("Response Time: {}ms", duration);
    }
}

在上面的代码中,我们重写了两个方法:preHandleafterCompletionpreHandle 方法会在请求被处理之前调用,我们可以在这里记录请求的 URL、HTTP 方法、请求 IP 等信息,并且可以记录当前的系统时间;afterCompletion 方法则会在请求处理完成后调用,我们在这里记录响应状态码、响应时间等信息。

2. 配置 Interceptor

我们需要将上面创建的拦截器配置到 SpringBoot 中,这样才能生效。一般情况下,我们会在 WebMvcConfigurer 类中进行拦截器的配置,具体代码如下:

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new RequestLogInterceptor())
                .addPathPatterns("/**");
    }
}

在上面的代码中,我们将 RequestLogInterceptor 注册到了 SpringBoot 的拦截器中,并且指定了拦截的路径为“/**”(表示拦截所有的请求)。

3. 查看日志

在我们完成了上面两部分的工作后,就可以启动 SpringBoot 应用程序,并访问任意 URL 来查看日志了。

假设我们当前的应用程序中有一个 /test 的 URL,在我们访问这个 URL 的时候,就会触发拦截器,记录请求和响应的信息,并将其输出到日志中。

例如,我们访问 localhost:8080/test,则会在日志中看到类似于以下的输出:

INFO  RequestLogInterceptor:16 - Request URL: http://localhost:8080/test,Method: GET
INFO  RequestLogInterceptor:17 - Request IP: 0:0:0:0:0:0:0:1
INFO  org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/].[dispatcherServlet]:227 - Initializing Spring DispatcherServlet 'dispatcherServlet'
INFO  org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/].[dispatcherServlet]:244 - Initializing Servlet 'dispatcherServlet'
INFO  org.apache.catalina.core.ApplicationContext.log:304 - Initializing Spring FrameworkServlet 'dispatcherServlet'
INFO  RequestLogInterceptor:24 - Response Status: 200
INFO  RequestLogInterceptor:25 - Response Time: 200ms

这样,我们就可以非常方便地记录请求和响应的信息,并将其输出到日志中了。

示例说明

下面通过两个示例来说明利用拦截器拦截请求信息收集到日志的过程。

示例一

假设我们当前的应用程序中有一个 /user 的 URL,用于查询用户的信息。我们希望在每次用户访问该 URL 的时候,记录用户的 IP 地址和请求的执行时间,并将其记录到日志中。

为了实现这个功能,我们需要创建一个拦截器,并在其中记录请求和响应的信息。具体代码如下:

public class UserRequestLogInterceptor extends HandlerInterceptorAdapter {

    private static final Logger logger = LoggerFactory.getLogger(UserRequestLogInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String ipAddress = request.getHeader("X-Real-IP");
        if (StringUtils.isEmpty(ipAddress)) {
            ipAddress = request.getRemoteAddr();
        }
        logger.info("User IP: {}", ipAddress);
        request.setAttribute("startTime", System.currentTimeMillis());
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        long startTime = (long) request.getAttribute("startTime");
        long duration = System.currentTimeMillis() - startTime;
        logger.info("User request execution time: {}ms", duration);
    }
}

在上面的代码中,我们新建了一个 UserRequestLogInterceptor 类,继承了 HandlerInterceptorAdapter 类,并重写了其中 preHandleafterCompletion 方法,用于在请求到达拦截器和处理完成之后分别记录用户 IP 和请求执行时间。

接下来,我们需要将 UserRequestLogInterceptor 注册到 SpringBoot 的拦截器中。在 WebMvcConfigurer 类中加入以下代码:

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new UserRequestLogInterceptor())
                .addPathPatterns("/user");
    }
}

在上面的代码中,我们只注册了 UserRequestLogInterceptor,并将其拦截的 URL 设置为 /user

如果我们现在访问 http://localhost:8080/user,则在控制台中可以看到以下输出:

INFO  UserRequestLogInterceptor:13 - User IP: 0:0:0:0:0:0:0:1
INFO  UserRequestLogInterceptor:20 - User request execution time: 3ms

以上输出表示,当前用户的 IP 地址为“0:0:0:0:0:0:0:1”,请求执行时间为“3ms”。

示例二

假设我们的应用程序中有一个 /login 的 URL,用于用户登录。我们需要在用户登录时记录用户的用户名和登录时间,并将其记录到日志中。

为了实现这个功能,我们需要创建一个拦截器,并在其中记录用户的信息。具体代码如下:

public class LoginRequestLogInterceptor extends HandlerInterceptorAdapter {

    private static final Logger logger = LoggerFactory.getLogger(LoginRequestLogInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String username = request.getParameter("username");
        logger.info("User login info: username={}, loginTime={}", username, new Date());
        return true;
    }
}

在上面的代码中,我们新建了一个 LoginRequestLogInterceptor 类,和之前类似继承了 HandlerInterceptorAdapter 类,并重写了其中的 preHandle 方法。在该方法中,我们记录了用户的用户名和登录时间,并将其记录到日志中。

接下来,我们需要将 LoginRequestLogInterceptor 注册到 SpringBoot 的拦截器中。同样在 WebMvcConfigurer 类中加入以下代码:

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginRequestLogInterceptor())
                .addPathPatterns("/login");
    }
}

在上面的代码中,我们只注册了 LoginRequestLogInterceptor,并将其拦截的 URL 设置为 /login

如果我们现在访问 http://localhost:8080/login?username=test,则在控制台中可以看到以下输出:

INFO  LoginRequestLogInterceptor:13 - User login info: username=test, loginTime=Tue Apr 27 15:08:01 CST 2021

以上输出表示,当前用户的用户名为“test”,登录时间为“Tue Apr 27 15:08:01 CST 2021”。