保卫你的应用:探索过滤器和拦截器的奥秘

前言

在现代Web开发中,安全性和性能是至关重要的因素。过滤器和拦截器是Web应用中的两个关键概念,它们可以帮助你保护你的应用免受恶意攻击,同时还可以实现各种功能,从日志记录到性能优化。这两个概念可能听起来有些抽象,但实际上它们就像是你应用的护卫者,站在前线,确保一切都在掌握之中。在本文中,我们将深入探讨过滤器和拦截器的作用、差异以及如何在你的项目中充分利用它们。

概述

拦截器和过滤器都使用了AOP的编程思想,都可以实现诸如日志记录、登录鉴权等功能,但二者的不同点也是比较多的
过滤器(Filters)和拦截器(Interceptors)是在Web开发中用于处理HTTP请求和响应的关键组件,它们用于执行一些特定的任务,如请求预处理、响应处理、日志记录、安全验证等。以下是它们的基本介绍以及在Web开发中的角色:

过滤器(Filters)

  • 基本介绍:过滤器是Servlet规范中的一部分,它是一个可插入的组件,用于在请求进入Servlet容器之前或响应离开容器之后对请求和响应进行预处理或后处理。
  • 角色:过滤器的主要角色是对HTTP请求和响应进行全局性的预处理和后处理。它们可以用于执行以下任务:
    • 认证和授权:验证用户身份并授予权限。
    • 日志记录:记录请求和响应的信息,以便监控和分析。
    • 数据压缩:在服务器端压缩响应数据以减小带宽占用。
    • 编码转换:将请求和响应的字符编码转换为指定的格式。
    • 请求参数处理:对请求参数进行验证、过滤或修改。
    • 缓存控制:管理浏览器缓存,提高性能。

拦截器(Interceptors)

  • 基本介绍:拦截器是在Spring框架中的一部分,它提供了一种机制,允许开发人员在请求处理的不同阶段执行自定义逻辑。
  • 角色:拦截器的主要角色是在Spring框架中对请求和响应进行拦截和处理。它们通常用于以下任务:
    • 权限验证:验证用户是否有权限执行某个操作。
    • 日志记录:记录请求和响应的信息,以进行审计或分析。
    • 性能监测:测量请求处理的性能,检测潜在的性能问题。
    • 异常处理:捕获并处理请求处理中的异常。
    • 国际化:处理多语言支持和区域设置。
    • 缓存控制:管理响应的缓存策略。

区别和选择

  • 过滤器是Servlet规范的一部分,而拦截器是Spring框架的一部分。因此,如果你使用Servlet容器(如Tomcat)来开发Web应用,你可以使用过滤器。如果使用Spring框架,可以选择使用拦截器。
  • 过滤器是全局性的,它们在Servlet容器级别操作,而拦截器是基于Spring MVC框架的,它们在控制器级别操作。
  • 过滤器通常更适用于低级别的任务,如字符编码、缓存控制等。拦截器通常更适合于高级别的任务,如权限验证、日志记录等。
  • 在实际应用中,可以根据任务的性质和框架选择来决定是使用过滤器还是拦截器,有时两者可以结合使用以实现不同层次的处理。

实现原理不同

拦截器和过滤器底层实现方式大不相同,过滤器是基于函数回调的,拦截器则是基于java的反射机制(动态代理)实现的。

我们自定义的过滤器中都会实现一个doFIlter()方法,这个方法有一个FilterChain参数,而实际上它是一个回调接口。Application FilterChain是它的实现类,这个实现类内部也有一个doFilter()方法就是回调方法。

public interface FilterChain {
    void doFilter(ServletRequest var1, ServletResponse var2) throws IOException, ServletException;
}

ApplicationFilterChain里面能拿到我们自定义的xxxFilter类,在其内部回调方法doFilter()里面调用各个自定义xxxFilter过滤器,并执行doFilter()方法

public final class ApplicationFilterChain implements FilterChain {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response) {
            ...//省略
            internalDoFilter(request,response);
    }
 
    private void internalDoFilter(ServletRequest request, ServletResponse response){
    if (pos < n) {
            //获取第pos个filter    
            ApplicationFilterConfig filterConfig = filters[pos++];        
            Filter filter = filterConfig.getFilter();
            ...
            filter.doFilter(request, response, this);
        }
    }
 
}

每个xxxFilter会先执行自身的doFilter()过滤逻辑,最后在执行结束前会执行filterChain.doFilter(servletRequest,servletResponse),也就是回调Application FilterChain的doFilter()方法,以此循环执行实现函数回调。

@Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        filterChain.doFilter(servletRequest, servletResponse);
    }

使用范围不同

我们看到过滤器实现的是javax.servlet.Filter接口,而这个接口是在servlet规范中定义的,也就是说过滤器Filter的使用要依赖于Tomcat等容器,导致它只能在web程序中用。

而拦截器(Interceptor)它是一个Spring组件,并由Spring容器管理,并不依赖Tomcat等容器。是可以单独使用的。不仅能应用在web程序汇总,也可以用于Application、Swing等程序中。

过滤器(Filters)和拦截器(Interceptors)在使用范围上有一些不同,这取决于它们所属的技术框架以及其执行的阶段和任务。以下是它们的使用范围的不同之处:

过滤器(Filters)的使用范围

  1. Servlet容器级别:过滤器是Servlet规范的一部分,因此它们在Servlet容器级别操作。这意味着它们可以应用于任何基于Servlet的Web应用程序,不依赖于特定的框架。

  2. 低级别任务:过滤器通常用于处理HTTP请求和响应的低级别任务,如字符编码、缓存控制、压缩、请求参数处理等。它们可以修改请求和响应的底层内容。

  3. 全局性处理:过滤器能够对整个Web应用程序的请求和响应进行全局性处理,因此可以应用于多个URL模式下的请求。

拦截器(Interceptors)的使用范围

  1. Spring MVC框架级别:拦截器是Spring MVC框架的一部分,因此它们在Spring应用程序中使用。拦截器只对Spring MVC控制器处理的请求生效。

  2. 高级别任务:拦截器通常用于处理与业务逻辑相关的高级别任务,如权限验证、日志记录、性能监测、国际化、异常处理等。它们更专注于业务逻辑。

  3. 控制器级别处理:拦截器只拦截Spring MVC控制器处理的请求,因此可以根据需要选择性地应用于特定的控制器或URL模式。

总结:

  • 过滤器是Servlet规范的一部分,可用于所有基于Servlet的Web应用程序,用于低级别任务,全局性处理。
  • 拦截器是Spring MVC框架的一部分,仅适用于Spring应用程序,用于高级别任务,控制器级别处理。
  • 选择过滤器或拦截器取决于你的应用程序需求和所使用的技术框架。通常,过滤器用于处理通用的HTTP请求和响应操作,而拦截器用于处理与业务逻辑相关的任务。

触发时机不同

过滤器和拦截器的触发时机也不同,如下图

image-20220403151925186

过滤器Filter是在请求进入容器后,但在进入servlet之前进行预处理,请求结束是在servlet处理完以后

拦截器Interceptor是在请求进入servlet后,在进入Controller之前进行预处理的,Controller中渲染了对应的视图之后请求结束。

注入Bean情况不同

在Spring Boot应用程序中,使用过滤器(Filters)和拦截器(Interceptors)时,注入Bean的方式有一些不同,这取决于它们所属的技术框架和生命周期管理。以下是过滤器和拦截器注入Bean的不同之处:

过滤器(Filters)的注入Bean

  1. 过滤器是Servlet规范的一部分,它们通常不是由Spring容器管理的Bean。因此,过滤器的生命周期由Servlet容器管理,而不是Spring容器。

  2. 你不能直接使用Spring的依赖注入(如@Autowired)来注入其他Spring Bean到过滤器中,因为过滤器实例通常不受Spring的控制。

  3. 为了在过滤器中使用Spring的Bean,你可以通过Spring的WebApplicationContextUtils工具类获取ApplicationContext,然后从中获取所需的Bean。

示例代码:

import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

public class MyFilter implements Filter {
    private MyService myService;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        ApplicationContext context = WebApplicationContextUtils
                .getRequiredWebApplicationContext(filterConfig.getServletContext());
        myService = context.getBean(MyService.class);
    }

    // ...
}

拦截器(Interceptors)的注入Bean

  1. 拦截器是Spring MVC框架的一部分,它们通常是由Spring容器管理的Bean。因此,你可以直接使用Spring的依赖注入来注入其他Spring Bean到拦截器中。

  2. 你可以使用@Autowired@Resource等注解将其他Spring Bean注入到拦截器中,这使得在拦截器中使用Spring管理的服务和组件变得非常方便。

示例代码:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

@Component
public class MyInterceptor implements HandlerInterceptor {
    private MyService myService;

    @Autowired
    public MyInterceptor(MyService myService) {
        this.myService = myService;
    }

    // ...
}

总结:

  • 过滤器通常不是由Spring容器管理的Bean,因此在过滤器中注入Spring Bean 需要使用WebApplicationContextUtils等方式来手动获取Spring容器中的Bean。
  • 拦截器通常是由Spring容器管理的Bean,因此你可以使用常规的Spring依赖注入方式(如@Autowired)来注入其他Spring Bean 到拦截器中,这更加便捷。

springboot中的实现

理解过滤器和拦截器的差异,让我们以一个基于Spring Boot的用户认证示例为例,展示如何使用过滤器和拦截器来实现用户认证。

场景:我们将创建一个Spring Boot Web应用程序,其中包含一个受保护的资源,只有已登录的用户才能访问。我们将使用过滤器和拦截器分别来实现这个认证逻辑。

项目设置:首先,确保你有一个Spring Boot项目的基础设置。

使用过滤器的示例

  1. 创建一个自定义过滤器类,例如AuthenticationFilter,来检查用户是否已登录。
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;

public class AuthenticationFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        // 在这里检查用户是否已登录,例如从Session中获取用户信息
        // 如果用户未登录,可以重定向到登录页面
        // 如果用户已登录,允许请求继续执行
        chain.doFilter(request, response);
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 初始化过滤器(可选)
    }

    @Override
    public void destroy() {
        // 销毁过滤器(可选)
    }
}
  1. 在Spring Boot应用程序中注册过滤器。
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FilterConfig {
    @Bean
    public FilterRegistrationBean<AuthenticationFilter> authenticationFilter() {
        FilterRegistrationBean<AuthenticationFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new AuthenticationFilter());
        // 设置需要过滤的URL模式
        registrationBean.addUrlPatterns("/protected/*"); // 这里假设受保护的资源在/protected/下
        return registrationBean;
    }
}

使用拦截器的示例

  1. 创建一个拦截器类,例如AuthenticationInterceptor,来检查用户是否已登录。
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class AuthenticationInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        // 在这里检查用户是否已登录,例如从Session中获取用户信息
        // 如果用户未登录,可以重定向到登录页面
        // 如果用户已登录,返回true允许请求继续执行,或者返回false阻止请求继续执行
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {
        // 请求处理后执行的操作(可选)
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
                                Exception ex) throws Exception {
        // 完成请求后执行的操作(可选)
    }
}
  1. 在Spring Boot应用程序中注册拦截器。
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 InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new AuthenticationInterceptor())
                .addPathPatterns("/protected/**"); // 这里假设受保护的资源在/protected/下
    }
}

在上述示例中,无论你选择使用过滤器还是拦截器,它们都用于拦截请求并执行用户认证逻辑。关于具体的用户认证逻辑(例如如何检查用户是否已登录),需要根据你的应用程序和需求来实现。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只牛博

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值