目录
为了保证所有接口访问记录可控可查,目前需要将所有核心系统的接口、后门jsp等做访问记录日志打印,其中要包括登陆人、时间、请求参数、接口URI等,实现方式有很多,可以使用过滤器、拦截器、aop切面、log4j框架等,由于要登录人信息,因此这个过滤器还需要实现登陆认证功能。还有一个问题在于需要在日志中打印出请求参数,如果是post请求,请求体通过流读取只能被读取一次,如果在过滤器读取请求体后,后续读取的结果为空,因此也需要特殊处理。本文给大家介绍一下我们使用的 Spring 中一种特殊类型的 Filter(过滤器)OncePerRequestFilter。
OncePerRequestFilter 是什么?
Filter 可以在 Servlet 执行之前或之后调用。当请求被调度给一个 Servlet 时,RequestDispatcher 可能会将其转发给另一个 Servlet。另一个 Servlet 也有可能使用相同的 Filter。在这种情况下,同一个 Filter 会被调用多次。
一个请求会经过两个 Servlet 处理的典型场景是请求的转发(Forwarding)或者包含(Include)。
-
请求转发(Forwarding): 当一个 Servlet 接收到一个请求后,它可以将请求转发给另一个 Servlet 处理。这种情况下,请求会经过第一个 Servlet,然后被转发给第二个 Servlet。在第二个 Servlet 处理完毕后,响应会返回给第一个 Servlet,最终返回给客户端。
-
请求包含(Include): 当一个 Servlet 接收到一个请求后,它可以包含(Include)另一个 Servlet 处理。这种情况下,请求也会经过第一个 Servlet,然后被包含到第二个 Servlet 中进行处理。处理完成后,响应会返回给第一个 Servlet,最终一起返回给客户端。
以下给一个FIlter可能被调用多次的场景:
// Filter1.java
public class Filter1 implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("Filter1 - before Servlet1");
chain.doFilter(request, response); // 继续调用过滤器链中的下一个过滤器或者目标 Servlet
System.out.println("Filter1 - after Servlet1");
}
}
// Filter2.java
public class Filter2 implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("Filter2 - before Servlet1");
chain.doFilter(request, response); // 继续调用过滤器链中的下一个过滤器或者目标 Servlet
System.out.println("Filter2