百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

过滤器(Filter)拦截器(Interceptor)的区别

haoteby 2025-01-17 11:47 1 浏览

前言

最近在Review代码时,发现有些同事在做请求信息增强处理时,有用到Filter过滤器,有用到Interceptor拦截器。虽然所做的需求都能用这两个达到效果了,但感觉同事对于这两个的区别还是有点分不清,甚至也不知道这两者在请求链路上处在什么位置,作用是什么。今天就整理了一下,把了解到的用图解出来,帮助大家理解这个Filter与Inteceptor的区别,以及后面如何使用这两者。

概念


一、过滤器

过滤器(Filter)属于Servlet的范畴, 通过实现javax.servlet.Filter接口来实现功能。 主要用于对用户请求进行预处理,是个典型的处理链。如果我们用的Spring框架,在javax.servlet.Filter的实现类中无法使到IOC容器中的Bean。因此它的作用范围要相对窄些。通常使用的场景:记录日志信息,解码,恶意请求的过滤,获取输入/输出流进行二次修改。

Filter具体流程可以分为以下几步:

1、filter的执行在Servlet之前,拦截请求过来的ServletRequest;

2、可根据需要自主地修改ServletRequest的请求信息,如Header等。

3、 在ServletResponse到达客户端之前,拦截ServletResponse

创建Filter必须实现javax.servlet.Filter接口,该接口定义了3个方法:

    /**
     * 初始化。被Web容器调用并将其放置service上。
     * 实例化filter后会被servlet容器仅且调用一次该方法进行初始化工作。
     * 该初始化工作必须完成后才能使用到过滤功能。若发生异常,无法使用该过滤器的过滤功能。
     */
    public void init(FilterConfig filterConfig) throws ServletException;


    /**
     * 处理过滤器过滤工作。可对ServletRequest,ServletResponse做统一处理,可修改头部信息,多次读取响应流(需自行实现ServletRequest)等。
     * 在客户端请求资源时会调用到doFilter这个方法。传入此方法的FilterChain会以链式调用传到下一个过滤器上。
     */
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException;


    /**
     * 销毁。该方法会被Web容器调用一次进行资源回收。
     */
    public void destroy();

其中doFilter就是实现过滤功能的核心方法,此方法上可以对 ServletRequest 预处理和 ServletResponse 后处理。

二、拦截器

拦截器(Inteceptor)属于Springframework的范畴, 通过实现
org.springframework.web.servlet.HandlerInterceptor接口来实现功能。 这些实现类更贴近我们的业务,深入到Action的前后。通常使用的场景:校验用户权限,对控制器中的Action做增强,统一响应内容等。

创建Inteceptor必须实现
org.springframework.web.servlet.HandlerInterceptor接口,该接口定义了3个方法:

    /**
     *
     * 该方法在具体的请求(Action)之前执行。拦截器也是一个链式执行处理的过程。
     * DispatcherServlet通过HandlerMapping找到N个拦截器,并执行拦截器的各个方法。
     * 每个拦截器都能决定是否中止执行执行链。
     */
    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {


        return true;
    }


    /**
     * 该方法在具体的请求(Action)之后执行。但在DispatcherServlet进行渲染视图之前。可以对Controller调用之后的ModelAndView进行操作
     */
    default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            @Nullable ModelAndView modelAndView) throws Exception {
    }


    /**
     * 该方法在DispatcherServlet进行渲染视图之后执行。主要用于资源清理
     */
    default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
            @Nullable Exception ex) throws Exception {
    }

由接口的定义可以看出,每个方法都有一个默认的实现方法,也就是说,在实现HandlerInterceptor接口时,不必每个接口都需要自行实现,只需要有针对地对对应的方法进行实现就可以。但有一点需要注意的是,preHandle方法必须返回true,后面的操作才能进行下去。


我们再看看这两者在请求链上的所在位置



我们编写一个例子来看看过滤器与拦截器的调用位置与方式有啥不同。

1、先定义一个Controller:

/**
* @author kingman
* @since 2021-01-04 13:47
*/
@RequestMapping("home")
@Controller
public class HomeController {


    @RequestMapping("sayhello")
    @ResponseBody
    public String sayHello()
    {
        System.out.println("HomeController sayHello method");

        return "hello";
    }
}

2、再定义一个Filter,前文提到,要做一个过滤器,就要实现javax.servlet.Filter这个接口:

/*** @author kingman* @since 2021-01-04 13:49*/@WebFilter(filterName = "filterDemo",urlPatterns = "/home/sayhello")@Componentpublic class FilterDemo implements javax.servlet.Filter {    @Override    public void init(FilterConfig filterConfig) throws ServletException {        System.out.println("FilterDemo init method");    }    @Override    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {        System.out.println("Before FilterDemo doFilter method");        filterChain.doFilter(servletRequest,servletResponse);        System.out.println("After FilterDemo doFilter method");    }    @Override    public void destroy() {        System.out.println("FilterDemo destroy method");    }}

3、再定义一个拦截器,同样地实现org.springframework.web.servlet.HandlerInterceptor接口,代码如下:

/**
* @author kingman
* @since 2021-01-04 13:51
*/
@Component
public class InteceptorDemo implements HandlerInterceptor {


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        System.out.println("InteceptorDemo preHandle method");

        return true;
    }


    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

        System.out.println("InteceptorDemo postHandle method");
    }


    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

        System.out.println("InteceptorDemo afterCompletion method");
    }
}

把拦截器注册到拦截器列表中

/**
* @author kingman
* @since 2021-01-04 13:54
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {


    @Resource
    private InteceptorDemo inteceptorDemo;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(inteceptorDemo).addPathPatterns("/home/sayhello");
    }
}

4、启动项目,运行
http://localhost:8080/home/sayhello,查看日志:


我们整理一下整个过程的执行顺序

Filter.init->

Before Filter.doFilter->

HandlerInterceptor.preHandle->

HandlerInterceptor.postHandle->

HandlerInterceptor.afterCompletion->

After Filter.doFilter


从这里的输出看出了从客户端请求到过滤器到Servlet到拦截器到控制器再往上返回响应内容的过滤,也印证了上述请求链的那张图的正确性。

这里只是一个例子,我们能在Filter能做什么,Interceptor能做什么,在什么时候做,这样已经一目了然了,至于它们的工作范围,就交由使用方去决定了。


扩展:

上述只是一个比较粗粒度的例子,再深挖可以去了解到Servlet在Spring中是如何应用处理请求的。以下也给了一个整理后的图,以后有时间也出一篇关于Servlet的请求链分析。


相关推荐

简单Labview实操案例

有几位条友私信我说Labview是怎么学的,怎么才能学好Labview,今天给大家简单介绍一下,如果想学上位机,Labview是相对来说比较容易上手的,而且开发速度也比较快,但是运行时候比较吃内存,...

关于LabVIEW用于仪器测控的自动测试程序的程序框架的选择问题!

有很长一段时间没有在公众号平台上输出、总结关于LabVIEW的知识文字内容了!主要是这段时间自己本职工作任务甚为繁重,加上各种家庭事宜的牵绊,耗费了过多的时间和精力,也就无力及时更新了。今天是端午节假...

LabVIEW编程基础:分割条控件的使用

1、分割条控件简介同其它高级编程语言类似,在LabVIEW中分割条控件也是界面设计中常用的一种控件元素,利用分割条控件可以将前面板划分为多个独立的区域,每个区域都是一个单独的窗格,这些窗格具有前面板的...

csgo一直显示正在连接到csgo网络怎么办?三招帮你解决

  CSGO是一款射击类的游戏,它的全名叫反恐精英:全球攻势,是一款由VALVE与HiddenPathEntertainment合作开发、ValveSoftware发行的第一人称射击游戏,相信很...

cs1.6没有bot怎么办

Hi~大家好啊,这里是聚合游戏,每天为你分享游戏相关的内容,喜欢的快来关注哟~...

《反恐精英:全球攻势2》 漏洞暴露玩家的IP地址

#文章首发挑战赛#据报道,在全球知名的电子游戏——CS2(《反恐精英:全球攻势2》)中存在一个HTML注入漏洞,这个漏洞被广泛利用来在游戏中注入图片并获取其他玩家的IP地址。...

《电子宠物》《007黄金眼》《雷神之锤》入选世界电子游戏名人堂

世界电子游戏名人堂5月8日公布了新的四位入选者《防卫者》《电子宠物》《007黄金眼》和《雷神之锤》,以向改变游戏行业规则的经典游戏致敬。世界电子游戏名人堂每年都会表彰那些具有持久热度并对视频游戏行业或...

V社修复《反恐精英2》游戏漏洞:可抓取玩家IP地址、发起XSS攻击

IT之家12月12日消息,Valve旗下《反恐精英2》游戏被曝光新的安全漏洞,攻击者通过注入恶意代码来抓取玩家的IP地址,并能对同一游戏大厅中的所有玩家发起跨站脚本攻击(XSS)。攻击...

粉丝自制《CS》1.6重制版将于2025年登陆Steam

基于Valve官方起源引擎SDK,由多位“CSPromod”粉丝项目前开发人员从头构建的《反恐精英》1.6版本重制版《CS:Legacy》日前宣布将于2025年在Steam发布。开发团...

知名网游源代码泄漏 ,外挂潮将来?

SteamDatabase近日发布消息称Valve旗下游戏《反恐精英:全球攻势》(CS:GO)与《军团要塞2》(TF2)的源代码疑遭泄露。据了解,游戏源代码如果泄露的话,黑客可以更为轻松地开发出外挂,...

Pandas每日函数学习之apply函数

...

求斐波那契数列(Fibonacci Numbers)算法居然有9种,你知道几种?

ByLongLuo斐波那契数列...

三维基因组:Loop结构 差异分析(2)

通过聚合峰分析进行可视化既然已经找出了“WT”和“FS”条件之间的差异loop结构,就可以利用聚合峰分析(APA)来直观地展示loop结构调用的质量。APA是一种以Hi-C数据中的中心loop像...

用Excel制作动态图表(动态名称法)

动态图表也称交互式图表,指图表的内容可以随用户的选择而变化,是图表分析中比较高级的形式。使用动态图表能够突出重点数据,避免被其他不需要的数据干扰,从而提高数据分析效率。一个好的动态图表,可以让人从大量...

Prometheus PromQL语法简介

...