过滤器与拦截器对比

在Java Web开发中,过滤器(Filter)和拦截器(Interceptor)都是用于处理请求和响应的机制,但它们在使用场景、实现方式和功能上有一些重要的区别。 

过滤器(Filter)

特点:
  1. 工作原理

    • 过滤器是在请求到达Servlet之前或响应离开Servlet之后进行处理的。
    • 过滤器可以对请求和响应进行修改。
  2. 配置方式

    • 通过web.xml文件进行配置,或使用注解(如@WebFilter)进行声明。
  3. 适用范围

    • 主要用于对请求进行预处理(如日志记录、权限检查、请求编码等)或对响应进行后处理。
示例代码:
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebFilter("/*") // 过滤所有请求
public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 初始化代码
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        // 记录请求信息
        System.out.println("Request URL: " + httpRequest.getRequestURL());

        // 继续执行后续的请求处理
        chain.doFilter(request, response);

        // 记录响应信息
        System.out.println("Response Status: " + httpResponse.getStatus());
    }

    @Override
    public void destroy() {
        // 清理资源
    }
}

过滤器的触发过程

  1. 请求到达Servlet容器: 当用户发送一个HTTP请求时,请求首先到达Servlet容器(例如Apache Tomcat)。

  2. 过滤器链的构建: Servlet容器根据配置(如web.xml文件或@WebFilter注解)构建一个过滤器链。这个链条中包含了所有需要处理该请求的过滤器。

  3. 过滤器的调用顺序: 过滤器的调用顺序是根据它们在配置中的排列顺序来决定的。首先执行第一个过滤器的doFilter方法。

  4. 执行doFilter方法: 在每个过滤器的doFilter方法中,开发者可以实现对请求和响应的处理逻辑,比如:

    • 记录请求信息
    • 进行权限检查
    • 修改请求或响应的内容

    代码示例:

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
    
        // 记录请求信息
        System.out.println("Request URL: " + httpRequest.getRequestURL());
    
        // 继续执行后续的请求处理
        chain.doFilter(request, response); // 继续调用下一个过滤器或目标Servlet
    
        // 记录响应信息
        System.out.println("Response Status: " + httpResponse.getStatus());
    }
  5. 继续执行后续过滤器或目标Servlet: 在doFilter方法中调用chain.doFilter(request, response)后,请求将继续传递到下一个过滤器(如果存在)或最终的目标Servlet。

  6. 响应返回: 一旦目标Servlet处理完请求并生成响应,响应将返回到过滤器。每个过滤器的doFilter方法可以在此时对响应进行后处理。

  7. 过滤器的销毁: 当应用程序被关闭或过滤器被卸载时,Servlet容器会调用过滤器的destroy方法,进行资源清理。

总结

  • 过滤器的触发是由Servlet容器在请求到达Servlet之前和响应离开Servlet之后自动管理的。
  • 过滤器可以对请求和响应进行处理,并通过chain.doFilter方法控制请求的流向。
  • 过滤器的配置可以通过web.xml文件或使用注解(如@WebFilter)进行声明。

1. 过滤器的顺序由配置决定

无论是通过web.xml配置还是使用注解(如@WebFilter),过滤器的执行顺序都是根据它们在配置中的排列顺序决定的。

1.1 通过 web.xml 指定顺序

web.xml中,过滤器的顺序是由它们的定义顺序决定的。例如:

xml

<filter>
    <filter-name>FirstFilter</filter-name>
    <filter-class>com.example.FirstFilter</filter-class>
</filter>
<filter>
    <filter-name>SecondFilter</filter-name>
    <filter-class>com.example.SecondFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>FirstFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<filter-mapping>
    <filter-name>SecondFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

在这个配置中,FirstFilter会在SecondFilter之前被调用。

拦截器(Interceptor)

特点:
  1. 工作原理

    • 拦截器是在请求到达Controller之前或响应离开Controller之后进行处理的。
    • 拦截器通常用于Spring MVC等框架中。
  2. 配置方式

    • 通过Spring配置文件或使用注解(如@Component)进行声明。
  3. 适用范围

    • 主要用于对请求进行预处理(如权限验证、日志记录)或对响应进行后处理。
 

1. 拦截器的触发

拦截器的触发通常与Spring MVC的请求处理过程密切相关。当用户发送HTTP请求时,Spring MVC会根据请求的URL映射到相应的Controller方法。在请求到达Controller之前,拦截器的preHandle方法会被调用。

2. 示例代码

 记录请求的时间、验证用户的角色、限制访问频率等。

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

@Component
public class MyInterceptor implements HandlerInterceptor {

    // 用于限制访问频率的简单计数器
    private Map<String, Long> requestCounts = new HashMap<>();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 记录请求信息
        System.out.println("Request URL: " + request.getRequestURL());
        System.out.println("Request Time: " + System.currentTimeMillis());

        // 权限验证示例
        String userRole = (String) request.getSession().getAttribute("userRole");
        if (userRole == null || !userRole.equals("ADMIN")) {
            response.setStatus(HttpServletResponse.SC_FORBIDDEN); // 无权限
            return false; // 终止请求
        }

        // 限制访问频率示例
        String clientIp = request.getRemoteAddr();
        Long lastRequestTime = requestCounts.get(clientIp);
        if (lastRequestTime != null && System.currentTimeMillis() - lastRequestTime < 1000) {
            response.setStatus(HttpServletResponse.SC_TOO_MANY_REQUESTS); // 频率限制
            return false; // 终止请求
        }
        requestCounts.put(clientIp, System.currentTimeMillis());

        return true; // 继续处理请求
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) {
        // 记录响应信息
        System.out.println("Response Status: " + response.getStatus());
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        // 清理资源
        System.out.println("Request completed.");
    }
}

3. 业务逻辑说明

  • 请求记录:记录请求的URL和时间,方便后续的调试和分析。
  • 权限验证:检查用户的角色是否为"ADMIN"。如果不是,则返回403 Forbidden状态,终止请求。
  • 访问频率限制:使用一个简单的HashMap来记录每个客户端IP的最后请求时间。若同一IP在1秒内发起多次请求,则返回429 Too Many Requests状态,限制其访问频率。

4. 如何触发拦截器

要触发这个拦截器,设置一个Controller,并确保请求的URL与该Controller的映射相匹配。例如:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

    @GetMapping("/admin")
    public String adminEndpoint() {
        return "Welcome to the admin page!";
    }
}

5. 配置拦截器

在Spring Boot应用中,在配置类中注册拦截器,并指定拦截的URL模式。如下所示:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    // 注册拦截器
    @Bean
    public MyInterceptor myInterceptor() {
        return new MyInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 配置拦截器的拦截条件
        registry.addInterceptor(myInterceptor())
                .addPathPatterns("/admin/**") // 拦截所有以/admin/开头的请求
                .excludePathPatterns("/public/**"); // 排除以/public/开头的请求
    }
}

6. 测试拦截器

  • 启动应用:运行Spring Boot应用程序。
  • 访问URL:在浏览器或Postman中访问http://localhost:8080/admin
  • 观察输出:查看控制台输出,确保拦截器的preHandlepostHandle方法被调用。

7. 不同测试场景

  • 未登录用户:在Session中不设置userRole,访问/admin,应该返回403状态。
  • 频率限制:在1秒内多次访问/admin,应该返回429状态。

8.配置拦截器链

在Spring配置中,可以通过WebMvcConfigurer接口来注册拦截器:

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new FirstInterceptor()).addPathPatterns("/**"); // 注册第一个拦截器
        registry.addInterceptor(new SecondInterceptor()).addPathPatterns("/**"); // 注册第二个拦截器
    }
}

9. 拦截器链的执行顺序

拦截器的执行顺序也是根据它们在addInterceptors方法中注册的顺序来决定的。以上述配置为例:

  1. FirstInterceptorpreHandle方法会在请求处理之前被调用。
  2. 然后调用SecondInterceptorpreHandle方法。
  3. 如果所有的preHandle方法返回true,请求会继续处理,最终调用目标Controller的方法。
  4. 请求处理完成后,控制权会返回到拦截器,依次调用postHandleafterCompletion方法。

关键区别

  • 过滤器:主要处理HTTP请求和响应的通用功能,适用于所有请求。它们在请求到达Servlet之前或响应离开Servlet之后执行。
  • 拦截器:主要处理特定业务逻辑的功能,适用于特定的业务方法调用。它们在特定方法调用之前和之后执行。

对比总结

特性过滤器(Filter)拦截器(Interceptor)
适用框架Java EE(Servlet)Spring MVC
处理时机请求到达Servlet之前和响应离开Servlet之后请求到达Controller之前和响应离开Controller之后
配置方式web.xml或注解Spring配置文件或注解
功能主要用于请求和响应的预处理和后处理主要用于请求的预处理和响应的后处理

具体使用场景

1. 请求日志记录
  • 场景描述:需要记录每个请求的详细信息(如请求 URL、请求时间等)。
  • 选择:使用过滤器
    • 原因:过滤器可以拦截所有请求,适合在请求到达Servlet之前进行日志记录。
2. 权限验证
  • 场景描述:在用户访问特定资源之前,需要验证用户的权限。
  • 选择:使用拦截器
    • 原因:拦截器可以在请求到达Controller之前进行处理,适合进行权限验证和拦截。
3. 请求参数处理
  • 场景描述:需要对请求参数进行统一处理,比如参数的格式化或编码。
  • 选择:使用过滤器
    • 原因:过滤器可以在请求到达Servlet之前处理请求参数,适合进行全局的请求参数处理。
4. 会话管理
  • 场景描述:需要在请求中检查用户的会话状态,确保用户已登录。
  • 选择:使用拦截器
    • 原因:拦截器可以在Controller处理请求之前检查会话状态,适合进行会话管理和用户认证。
5. 响应压缩
  • 场景描述:需要对响应数据进行压缩,以减少网络带宽的使用。
  • 选择:使用过滤器
    • 原因:过滤器可以在响应离开Servlet之前对响应数据进行处理,适合进行响应压缩。
6. 跨域请求处理
  • 场景描述:需要处理跨域请求,添加相应的CORS头信息。
  • 选择:使用过滤器
    • 原因:过滤器可以在请求到达Servlet之前添加必要的CORS头信息,适合进行跨域请求处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值