过滤器 Filter vs 拦截器 Interceptor

之前已经详细介绍过了过滤器Filter 和 拦截器Interceptor 了,本文将两种拦截请求的技术做一个对比讲解!

回顾:   过滤器Filter详解        拦截器Interceptor详解

一、过滤器 Filter

Filter,中文名过滤器,是 Servlet 规范中定义的一种拦截机制,如同应用的第一道防线——护城河,所有 HTTP 请求都要经过它的洗礼。它独立于 Spring 框架,地位超然,不受框架限制,任何 Web 应用都可以使用它来实现通用的请求处理逻辑。

1.1 Filter 的工作原理

想象一下,Web 应用就像一座城堡,而 Filter 就是城堡外围的护城河,所有进出城堡的请求都必须经过它。

  1. 请求抵达,Filter 拦截: 当浏览器发送请求到服务器时,请求首先会被 Servlet 容器拦截,就像任何访客都必须先经过护城河的检查。

  2. Filter 链,层层把关: 多个 Filter 可以组成一条链,按照预先定义的顺序依次对请求进行处理,就像护城河上设置了多道关卡,每道关卡都有不同的检查项目。

  3. FilterChain:放行或拦截的决定者: FilterChain 对象就像关卡的守卫队长,它负责调用 Filter 链中的下一个 Filter,或者在所有 Filter 执行完毕后将请求放行到目标资源,最终将响应返回给客户端。

  4. Filter 的生命周期:

    • init(FilterConfig): 在 Filter 初始化时调用一次,可以用来读取配置文件、初始化资源等,就像关卡建立时进行的准备工作。

    • doFilter(ServletRequest, ServletResponse, FilterChain): 每次请求都会调用,实现具体的过滤逻辑,就像每次检查访客都要执行的操作。

    • destroy(): 在 Filter 销毁时调用一次,可以用来释放资源,就像关卡拆除时进行的清理工作。

1.2 Spring Boot 中使用 Filter 

Spring Boot 为我们提供 @WebFilter 注解,让我们可以用更简洁、优雅的方式配置 Filter:

1.2.1 创建 Filter

@WebFilter(urlPatterns = {"/user/*", "/admin/*"}, filterName = "securityFilter") 
// 使用 @WebFilter 注解声明这是一个 Filter,并指定拦截路径和过滤器名称
public class SecurityFilter implements Filter { 

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 初始化资源,例如加载用户权限配置文件
        System.out.println("SecurityFilter 初始化...");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        // 1. 获取请求信息,例如请求路径、请求参数
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String requestURI = httpRequest.getRequestURI();

        // 2. 执行业务逻辑,例如校验用户登录状态、权限验证
        System.out.println("SecurityFilter 拦截到请求: " + requestURI);
        if (!isAuthenticated(httpRequest)) { // 模拟用户认证逻辑
            // 未通过验证,跳转到登录页面或者返回错误信息
            HttpServletResponse httpResponse = (HttpServletResponse) response;
            httpResponse.sendRedirect("/login"); // 跳转到登录页面
            return; 
        }

        // 3. 放行请求到下一个 Filter 或目标资源
        chain.doFilter(request, response);

        // 4. 后置处理,例如记录日志
        System.out.println("SecurityFilter 处理请求完成: " + requestURI);
    }

    @Override
    public void destroy() {
        // 释放资源
        System.out.println("SecurityFilter 销毁...");
    }

    // 模拟用户认证逻辑
    private boolean isAuthenticated(HttpServletRequest request) {
        // 这里可以根据实际需求实现,例如检查 Session 中是否存在用户信息
        return true; 
    }
}

1.2.2 配置 Filter

在 Spring Boot 应用启动类上添加 @ServletComponentScan 注解,自动扫描并注册 Filter:

@SpringBootApplication
@ServletComponentScan //  启用 Servlet 组件扫描,自动发现并注册 Filter
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

1.3 Filter 的应用场景
  • 安全防护: 就像城堡的护城河,Filter 是应用的第一道防线,可以用于实现统一的身份认证、权限校验、敏感信息过滤等安全控制。

  • 字符编码: 可以统一设置请求和响应的字符编码,避免中文乱码问题,就像统一了城堡内使用的语言。

  • 日志记录: 可以记录所有请求和响应的信息,方便排查问题、分析用户行为,就像城堡的史官记录着一切来往人员的信息。

  • gzip 压缩: 可以对响应数据进行 gzip 压缩,减少网络传输量,提高响应速度,就像优化了城堡的交通运输系统。

二、拦截器 Interceptor

Interceptor,中文名拦截器,是 Spring MVC 框架提供的一种更精细化的拦截机制,它专注于拦截控制器方法,就像城堡的城门守卫,只对进入城门的人进行检查。

2.1 Interceptor 的工作原理:三次拦截

想象一下,Interceptor 就像城堡的城门守卫,在客人进入房间之前、离开房间之后,以及处理房间事务的过程中,都会提供周到的服务:

  1. preHandle: 第一道关卡

    • 在目标方法执行之前执行,就像城门守卫在客人进入房间之前进行身份验证。

    • 可以修改请求参数、设置响应头信息、甚至终止请求的执行。

    • 返回 true 表示放行,继续执行下一个拦截器或目标方法;返回 false 则表示拦截,请求终止,就像城门守卫拒绝客人进入。

  2. postHandle: 第二道关卡

    • 在目标方法执行之后,视图渲染之前执行,就像城门守卫在客人离开房间,但还没走出城门时进行检查。

    • 可以修改模型数据、添加逻辑视图等,对响应进行二次加工。

    • 此时无法阻止请求的处理流程,因为目标方法已经执行完毕。

  3. afterCompletion: 最后一道关卡

    • 在请求处理完成后执行,包括视图渲染以及异常处理,就像城门守卫在客人离开城门后进行最后的记录工作。

    • 可以进行资源清理、记录日志等操作,无论请求是否成功都会执行。

2.2 Spring Boot 中使用 Interceptor 

2.2.1 创建 Interceptor

public class AuthInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 1. 获取请求信息,例如请求路径、请求参数
        String requestURI = request.getRequestURI();

        // 2. 执行业务逻辑,例如权限验证
        System.out.println("AuthInterceptor 拦截到请求: " + requestURI);
        if (!hasPermission(request)) { // 模拟权限验证逻辑
            //  如果验证失败,设置错误信息,并跳转到错误页面
            response.setStatus(HttpServletResponse.SC_FORBIDDEN); 
            request.setAttribute("message", "您没有权限访问该资源!");
            request.getRequestDispatcher("/error").forward(request, response);
            return false;
        }

        // 3. 放行请求
        System.out.println("AuthInterceptor 放行请求: " + requestURI);
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 修改模型数据,例如添加用户信息
        if (modelAndView != null) {
            modelAndView.addObject("username", "John Doe");
        }
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 记录日志信息
        System.out.println("AuthInterceptor 请求处理完成: " + request.getRequestURI());
        if (ex != null) {
            System.out.println("发生异常: " + ex.getMessage());
        }
    }

    // 模拟权限验证逻辑
    private boolean hasPermission(HttpServletRequest request) {
        // 这里可以根据实际需求实现,例如检查用户角色
        return true;
    }
}

2.2.2 配置 Interceptor

@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 添加拦截器,并配置拦截路径
        registry.addInterceptor(new AuthInterceptor())
                .addPathPatterns("/admin/**") // 拦截 /admin/ 下的所有请求
                .excludePathPatterns("/admin/login"); // 排除 /admin/login 请求
    }
}

2.3 Interceptor 的应用场景
  • 权限控制: 就像城堡的城门守卫,Interceptor 可以拦截特定 URL 的请求,验证用户权限,防止未授权访问。

  • 性能监控: 可以记录请求处理时间,分析系统性能瓶颈,就像城堡的计时器,记录每个访客的停留时间。

  • 日志记录: 可以记录用户的关键操作日志,例如登录、退出、修改信息等,就像城堡的记录员,记录着重要事件。

  • 国际化: 可以根据用户浏览器语言设置,选择合适的语言资源文件,就像城堡提供多语言导览服务。

三、Filter  vs  Interceptor

特性FilterInterceptor
规范Servlet 规范,不依赖 Spring 框架Spring MVC 框架的一部分
拦截范围所有 Web 应用,拦截所有请求仅限 Spring MVC 应用,拦截控制器方法
执行顺序Filter 链式调用,按配置顺序执行Interceptor 链式调用,按配置顺序执行
方法丰富度只有一个 doFilter 方法preHandle、postHandle、afterCompletion 三个方法
应用场景偏向底层、通用性需求,例如字符编码、安全过滤、Gzip 压缩偏向业务逻辑,例如权限控制、日志记录、性能监控

选择建议:

  • 优先考虑 Interceptor: 如果你的应用是基于 Spring MVC 构建的,并且需要对控制器方法进行拦截,那么优先选择 Interceptor,它更方便、更灵活。

  • Filter 也不可或缺: 如果你的需求与 Servlet API 相关,例如文件上传下载、字符编码设置等,或者你需要在 Spring MVC 应用之外使用拦截器,那么 Filter 是更好的选择。

  • 强强联手,灵活组合: 在实际项目中,可以根据需要组合使用 Filter 和 Interceptor,例如使用 Filter 进行字符编码设置,使用 Interceptor 进行权限控制,从而构建更完善的请求处理机制。

总结:

Filter 和 Interceptor 都是 Spring Boot 应用中不可或缺的请求拦截利器,它们就像城堡的护城河和城门守卫,在不同阶段、不同层面守护着应用的安全。开发者需要根据具体的应用场景选择合适的拦截器,并充分利用 Spring Boot 提供的便捷 API 和灵活的配置,才能构建出安全、高效、用户体验俱佳的 Web 应用。

以上就是关于过滤器Filter 和 拦截器Interceptor 的对比讲解了,希望对各位看官有所帮助,下期见,谢谢~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值