06_Filtering

Filtering

过滤器(Filter)是 Java 组件, 允许运行过程中改变进入资源的请求和资源返回的响应中的有效负载和 header
信息。

本章描述了 Java Servlet v3.0 API 类和方法,它提供了一种轻量级的框架用于过滤动态和静态内容。还描
述了如何在 Web 应用配置 Filter和它们实现的约定和语义。

网上提供servlet过滤器的API文档在。过滤器的配置语法由第14章“部署描述符”中的部署描述符模式给出。阅读本章时,读者应使用这些来作为参考。

1. 什么是过滤器

过滤器是一段可重用的代码,它可以转换HTTP请求、响应和头信息的内容。过滤器通常不会像servlet那样创建响应或响应请求,而是修改或调整资源的请求,并修改或调整资源的响应。

过滤器可以作用于动态或静态内容。为了本章的目的,动态和静态内容被称为Web资源。

对于需要使用过滤器的开发人员可用的功能类型如下:

  • 资源的访问请求之前调用它。
  • 一个资源请求的处理之前调用。
  • 通过包装定制版本的请求对象对请求头和数据的修改
  • 通过提供定制版本的响应对象对响应头和响应数据的修改。
  • 资源的调用的后拦截。
  • 以指定的顺序通过零,一个或多个过滤器操作servlet、servlet、组或静态内容。
1.1 过滤器组件例子
  • Authentication filters
  • Logging and auditing filters
  • Image conversion filters
  • Data compression filters
  • Encryption filters
  • Tokenizing filters
  • Filters that trigger resource access events
  • XSL/T filters that transform XML content
  • MIME-type chain filters
  • Caching filters

2.主要概念

本章描述了过滤器模型的主要概念。
应用程序开发人员通过实现javax.servlet.Filter接口创建一个过滤器,并提供一个不带参数的公共构造函数。该类及构建Web 应用的静态资源和 Servlet 打包在 Web 应用归档文件中。在部署描述符中使用元素声明过滤器。通过在部署描述符中定义元素,可以为过滤器或过滤器集合配置调用。可以使用 servlet 的
逻辑名把过滤器映射到一个特定的 servlet,或者使用 URL 模式把过滤器映射到一组 Servlet 和静态内容资源。

2.1 过滤器生命周期

The doFilter method of a filter will typically be implemented following this or some subset of the following pattern:
在部署Web应用程序之后,在请求导致容器访问Web资源之前,容器必须定位必须应用于Web资源的过滤器列表,如下所述。容器必须确保它已经为列表中的每个过滤器实例化了一个适当类的过滤器,并调用它的init(FilterConfig config)方法。这个过滤器可能会抛出一个异常来表示它不能正常工作。如果异常类型为UnavailableException,则容器可以检查异常的isPermanent属性,并在稍后的时间选择重试过滤器。

在部署描述符中,每个声明只有一个实例被实例化到容器的每个JVM中。容器提供过滤器部署描述符中声明的过滤器配置,用于Web应用程序的ServletContext的引用,以及初始化参数集。

当容器接收到一个传入请求时,它将在列表中获取第一个过滤器实例,并调用它的doFilter方法,传入ServletRequest和ServletResponse,并引用它将使用的FilterChain对象。

过滤器的doFilter方法通常会按照以下模式的某个子集实现:

  1. 该方法检查请求的header。

  2. 该方法可以用定制的ServletRequest或HttpServletRequest实现来包装请求对象,以修改请求头或数据。

  3. 该方法可以将响应对象封装到其doFilter方法中,并定制实现ServletResponse或HttpServletResponse来修改响应头或数据。

  4. 过滤器可以调用过滤器链中的下一个实体。下一个实体可能是另一个过滤器,或者如果调用的过滤器是这个链的部署描述符中配置的最后一个过滤器,那么下一个实体就是目标Web资源。下一个实体的调用是通过调用FilterChain对象上的doFilter方法来实现的,并在请求和响应中传递它可能已经创建的包装版本。过滤器链的doFilter方法的实现,由容器提供,必须在过滤器链中定位下一个实体,并调用它的doFilter方法,传入适当的请求和响应对象。或者,过滤器链可以阻止请求,而不是调用调用下一个实体,让过滤器负责填充响应对象。service方法需要在与应用于servlet的所有过滤器相同的线程中运行。

  5. 在调用链中的下一个过滤器之后,过滤器可以检查响应头。

  6. 或者,过滤器可能会抛出一个异常来指示处理中的错误。如果过滤器在其doFilter处理过程中抛出一个无法使用的异常,容器就不能尝试继续沿着过滤器链进行处理。如果异常不是永久性的,它可以选择在以后重新尝试整个链。

  7. 当调用链中的最后一个过滤器时,将访问的下一个实体是链末端的目标servlet或资源。

  8. 在过滤器实例可以被容器从服务中删除之前,容器必须首先调用过滤器上的destroy方法,以使过滤器能够释放任何资源并执行其他清理操作。

2.2包装请求和响应

过滤概念的核心是包装请求或响应的概念,以便它可以覆盖行为来执行过滤任务。在这个模型中,开发人员不仅有能力覆盖请求和响应对象上的现有方法,而且还能提供适合于特定筛选任务的新API,从而使过滤器或目标web资源沿着链向下。例如,开发人员可能希望将响应对象扩展到输出流或写入器的更高级别的输出对象,例如允许将DOM对象写回客户机的API。

为了支持这种类型的过滤器,容器必须支持以下要求。当一个过滤器调用容器的过滤器链上的doFilter方法实现中,容器必须确保它通过过滤器链中的下一个实体,或到目标web资源如果过滤器链中的最后一个的请求和响应对象,是通过调用过滤器传递到doFilter方法的相同的对象。

包装器对象标识的相同要求适用于从servlet或过滤器到RequestDispatcher的调用。或RequestDispatcher向前发展。包括,当调用者包装请求或响应对象时。在这种情况下,被调用的servlet所看到的请求和响应对象必须是通过调用servlet或过滤器传入的相同的包装器对象。

2.3 过滤器环境

在部署描述符中使用元素,可以将一组初始化参数关联到一个过滤器。这些参数的名称和值可以通过getInitParameter和getInitParameterNames方法在运行时通过过滤器的FilterConfig对象进行筛选。此外,FilterConfig提供了对Web应用程序的ServletContext的访问,用于加载资源、记录功能,以及在ServletContext的属性列表中存储状态。过滤器和过滤器链末端的目标servlet或资源必须在相同的调用线程中执行。

2.4 在一个Web应用中filter的配置

过滤器是通过@WebFilter注释定义的,如在规范的第8-72页中定义的“@WebFilter”或使用部署描述符中的 元素 。在这个元素中,程序员声明如下:

  • 过滤器名称:用于过滤器映射到一个servlet或URL

  • 过滤器类:容器使用来识别过滤器类型

  • 初始化:一个过滤器的初始化参数

可选地,程序员可以指定图标、文本描述和工具操作的显示名称。容器必须实例化定义在部署描述符中每个过滤器声明的过滤器的Java类的一个实例。因此,如果开发人员为同一个过滤器类生成两个过滤器声明,那么容器将实例化同一个过滤器类的两个实例。

下面是一个过滤器声明的例子:


Image Filter
com.example.ImageServlet

在部署描述符中声明了过滤器之后,汇编器使用filter-mapping>元素来定义Web应用程序中的servlet和静态资源。过滤器可以使用元素与servlet关联。例如,下面的代码示例将图像过滤器过滤器映射到ImageServlet servlet:


Image Filter
ImageServlet

Filters can be associated with groups of servlets and static content using the style of filter mapping:


Logging Filter
/*

这里,日志过滤器应用于Web应用程序中的所有servlet和静态内容页,因为每个请求URI都匹配“/*”URL模式。

当使用样式处理元素时,容器必须确定是否匹配请求URI,使用第12章中定义的路径映射规则,“将请求映射到servlet”。

在构建用于特定请求URI的筛选器链时,容器使用的顺序如下:

  1. 首先,匹配的过滤器映射与这些元素在部署描述符中出现的顺序相同。
  2. 接下来,匹配的过滤器映射与这些元素在部署描述符中出现的顺序相同。

如果一个筛选映射包含了,那么容器必须将筛选映射扩展到多个筛选映射(每个 and ),保存 and 元素的顺序。例如,下面的筛选器映射:


Multiple Mappings Filter
/foo/*
Servlet1
Servlet2
/bar/*

is equivalent to:


Multipe Mappings Filter
/foo/*


Multipe Mappings Filter
Servlet1


Multipe Mappings Filter
Servlet2


Multipe Mappings Filter
/bar/*

关于过滤器链顺序的要求意味着容器在接收到传入请求时按如下方式处理请求:
■根据第126页上的“映射规范”的规则标识目标Web资源。
■如果存在通过servlet名称匹配的过滤器并且Web资源具有,那么容器会按照部署描述符中声明的顺序构建匹配的过滤器链。该链中的最后一个过滤器对应于最后一个匹配过滤器,并且是调用目标Web资源的过滤器。
■如果存在使用匹配的过滤器并且根据第12.2节“映射规范”的规则匹配请求URI,则容器会构建匹配过滤器的链与部署描述符中声明的顺序相同。此链中的最后一个过滤器是此请求URI的部署描述符中的最后一个匹配过滤器。该链中的最后一个过滤器是调用匹配链中的第一个过滤器的过滤器,或者调用目标Web资源(如果没有)。

预计高性能Web容器将缓存过滤器链,以便它们不需要按照每个请求计算它们。

2.5 Filters and the RequestDispatcher

自Java Servlet规范2.4版以来的新增功能是能够配置被请求调度器(request dispatcher)的forward()和include()调用的过滤器。
通过在部署描述符中使用新的元素,开发人员可以指出过滤器映射是否希望在以下情况下将过滤器应用于请求:
1.请求直接来自客户端。这由具有值REQUEST的元素或没有任何元素指示。
2.请求正在被表示匹配的Web组件的请求调度程序下使用forward()调用所处理。这由具有值FORWARD的元素指示。
3.请求正在代表匹配的Web组件的请求分派器下使用include()进行处理。
呼叫。这由一个值为INCLUDE的元素表示。
4.该请求正在使用第112页上的“错误处理”中指定的错误页机制处理为与匹配的错误资源。这由具有值ERROR的元素指示。
5.该请求正在使用第10页上的“异步处理”中指定的异步上下文分派机制,通过调度呼叫处理到Web组件。这由具有值ASYNC的元素指示。
6.或上述1,2,3,4或5的任何组合。
例如:


Logging Filter
/products/*

会导致日志过滤器被客户端启动的/products/..请求调用,但不在请求分派器调用之下调用,其中请求分派器具有路径开始/ products/...。LoggingFilter将在请求最初的调度和恢复的请求时被调用。 以下代码:


Logging Filter
ProductServlet
INCLUDE

将导致日志过滤器不会被客户端请求调用到ProductServlet,也不会在请求dispatcher forward()调用下调用ProductServlet,而是会在请求调度程序include()调用中调用,其中请求分派器的名称以ProductServlet开始。下面的代码:


Logging Filter
/products/*
FORWARD
REQUEST

将导致Logging Filter被/products/...开头的请求和以/products/...开头的请求分发器forward()调用下调用。
最后,以下代码使用特殊的servlet名“*”


All Dispatch Filter
*
FORWARD

在按名字或按路径获取的所有请求分派器 forward()调用时该代码将导致 All Dispatch Filter 被调用。

你可能感兴趣的:(06_Filtering)