文章目录
body和header数据进行过滤和修改,对静态数据和动态数据过滤,具体的语法可以参考14章
6.1、什么是过滤器?
- 过滤器是一段可以重用的代码,它能够拦截Http请求和响应,同时header和body做一些修改适配,这个有点类似流水线,过滤器是就工人
- 可以多个过滤器完成过滤的功能,过滤器链
6.1.1、过滤器适用场景
- 认证过滤
- 日志和审计过滤
- 图片转换过滤
- 数据压缩过滤
- 加密过滤
- Tokening 过滤
- 访问事件触发过滤器
- XSL/T 过滤器和转换XML内容
- MIME-type 过滤链
- 缓存过滤器
6.2、主要概念
- 实现自定义过滤器,需要实现javax.servlet.Filter接口,提供无参构造方法,在web应用配置描述文件(web.xml)中配置( 和), 表示你自定义过滤器的类路径, filter-mapping 拦截资源的url 匹配
6.2.1、过滤器的生命周期
-
在使用过滤功能之前,首先需要实例化过滤器,就需要调用init(FilterConfig config)方法,这个方法可能会抛出异常,如果抛出是UnavailableException异常,那么容器会调用isPermanent属性判断是否需要重试
-
在单个JVM中有且仅有每个对应一个实例,也就单例
-
当一个请求过来之后,他们都会调用doFilter方法(组成一个过滤器链)
-
doFilter方法典型实现场景
- 判断request请求的头部信息
- 可能会包装自定义实现ServletRequest或HttpServletRequest对象,或者修改头部和主体
- 可能会包装自定义实现ServletResponse或HttpServletResponse对象,或者修改头部和主体
- doFilter可能调用下一个也是过滤器,也就另一个过滤器doFilter方法,这个就形成过滤器链(FilterChain),过滤器链如果没有调用下一个实体(资源或其他过滤器)的话可能会阻塞请求,对应过滤器链运行在同一个线程中
- 调用下一个过滤器,可能会验证以响应的头
- 执行过滤器链中可能会抛出异常(UnavailableException) 容器会根据isPermanent来判断是否需要随后重试,还直接终止请求
- 过滤器链最后被调用可能是目标Servlet或资源
- 在过滤实例化之前,servlet容器可以通过destroy方法去移除这个过滤器
6.2.2、包装请求和响应
- 支持改变请求或响应对象的内容
6.2.3、过滤器环境
- 通过 初始化参数, 在运行时候通过FilterConfig类的getInitParameter和getInitParameterNames方法来获取这些初始化参数,同时FilterConfig会存储ServletContext上下文的状态
6.2.4、在web应用配置过滤器
-
除了使用在部署配置web.xml文件中加入 配置过滤器,还可以通过@WebFilter来配置过滤器
-
@WebFilter具有参数
- filter-name: 使用过滤器映射到一个servlet或URL
- filter-class: 让容器识别过滤器的类型
- init-params; 为这个过滤器初始化参数
-
例子
-
<!--首先定义一个filter过滤器--> <filter> <filter-name> Image Filter</filter-name> <filter-class>com.acme.ImageServlet</filter-class> </filter> <!--定义过滤器映射到servlet上, 是通过filter-name进行关联的--> <filter-mapping> <filter-name>Image Filter</filter-name> <servlet-name>ImageServlet</servlet-name> </filter-mapping> <!--定义一个日志过滤器去匹配和拦截所有的URL--> <filter-mapping> <filter-name>Logging Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!--如果一个过滤器同时匹配url和servlet--> <filter-mapping> <filter-name>Multipe Mapping Filter</filter-name> <url-pattern>/foo/*</url-pattern> <servlet-name>Servlet1</servlet-name> <servlet-name>Servlet2</servlet-name> <url-pattern>/bar/*</url-pattern> </filter-mapping> <!--等同于下面--> <filter-mapping> <filter-name>Multipe Mappings Filter</filter-name> <url-pattern>/foo/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>Multipe Mappings Filter</filter-name> <servlet-name>Servlet1</servlet-name> </filter-mapping> <filter-mapping> <filter-name>Multipe Mappings Filter</filter-name> <servlet-name>Servlet2</servlet-name> </filter-mapping> <filter-mapping> <filter-name>Multipe Mappings Filter</filter-name> <url-pattern>/bar/*</url-pattern> </filter-mapping>
-
对于构建过滤链,可以缓存,提高web的性能
-
6.2.5、过滤器和请求转发器(RequestDispatcher)
-
从2.4的Servlet版本中 forward和include可以配置filters(过滤器链),进行一波重定向或其他操作都是可能匹配 从而经过过滤器拦截。
-
一些属性
- REQUEST
- FORWARD
- INCLUDE
- ERROR
- ASYNC
-
例子
-
<!--配置一个日志的过滤器映射, 主要是/products开头的url--> <filter-mapping> <filter-name>Logging Filter</filter-name> <url-pattern>/products/*</url-pattern> </filter-mapping> <!--客户请求不会直接调用,只有发生了include,才会匹配到日志过滤器--> <filter-mapping> <filter-name>Logging Filter</filter-name> <servlet-name>ProductServlet</servlet-name> <dispatcher>INCLUDE</dispatcher> </filter-mapping> <!--客户请求的url是/products开头,同时调用forward或request方法才会匹配到日志过滤器--> <filter-mapping> <filter-name>Logging Filter</filter-name> <url-pattern>/products/*</url-pattern> <dispatcher>FORWARD</dispatcher> <dispatcher>REQUEST</dispatcher> </filter-mapping> <!--所有servlet只要是调用了forward方法都会匹配到All Dispatch Filter过滤器--> <filter-mapping> <filter-name>All Dispatch Filter</filter-name> <servlet-name>*</servlet-name> <dispatcher>FORWARD</dispatcher> </filter-mapping>
-