Spring MVC 之过滤器
# Spring MVC 之过滤器
spring-web
模块提供了一些有用的 Filter:
- Form Data (opens new window)
- Forwarded Headers (opens new window)
- Shallow ETag (opens new window)
- CORS (opens new window)
# 表单内容过滤器
浏览器只能通过 HTTP GET 或 HTTP POST 提交表单数据,但非浏览器客户端也可以使用 HTTP PUT、PATCH 和 DELETE。 Servlet API 需要 ServletRequest.getParameter*()
系列方法来支持仅对 HTTP POST 的表单字段访问。
spring-web
模块提供了 FormContentFilter
来拦截内容类型为 applicationx-www-form-urlencoded
的 HTTP PUT、PATCH、DELETE 请求,从请求体中读取表单数据,并包装 ServletRequest
通过 ServletRequest.getParameter()
系列方法使表单数据可用。
# 转发过滤器
当请求通过代理(如负载均衡器)时,主机、端口和方案可能会发生变化,这使得从客户端角度创建指向正确主机、端口和方案的链接成为一项挑战。
RFC 7239 (opens new window) 定义了 Forwarded
HTTP 头,代理可以使用它来提供有关原始请求的信息。还有其他非标准头,包括 X-Forwarded-Host
、X-Forwarded-Port
、X-Forwarded-Proto
、X-Forwarded-Ssl
和 X-Forwarded-Prefix
。
ForwardedHeaderFilter
是一个 Servlet 过滤器,它修改请求以便 a) 根据 Forwarded
头更改主机、端口和 scheme;b) 删除这些头以消除进一步的影响。该过滤器依赖于包装请求,因此它必须排在其他过滤器之前,例如 RequestContextFilter
,它应该与修改后的请求一起使用,而不是原始请求。
Forwarded
头有安全考量,因为应用程序无法知道头是由代理按预期添加的,还是由恶意客户端添加的。这就是为什么应将信任边界处的代理配置为删除来自外部的不受信任的 Forwarded
头。还可以使用 removeOnly=true
配置 ForwardedHeaderFilter
,在这种情况下它会删除但不使用头。
为了支持异步请求 (opens new window)和错误分派,此过滤器应使用 DispatcherType.ASYNC
和 DispatcherType.ERROR
进行映射。如果使用 Spring Framework 的 AbstractAnnotationConfigDispatcherServletInitializer
(参见 Servlet Config (opens new window)),所有过滤器都会自动为所有调度类型注册。但是,如果通过 web.xml
或在 Spring Boot 中通过 FilterRegistrationBean
注册过滤器,请确保除了 DispatcherType.REQUEST
之外还包括 DispatcherType.ASYNC
和 DispatcherType.ERROR
。
# ETag 过滤器
ShallowEtagHeaderFilter
过滤器通过缓存写入响应的内容并从中计算 MD5 哈希来创建“浅”ETag。下次客户端发送时,它会做同样的事情,但它还会将计算值与 If-None-Match
请求标头进行比较,如果两者相等,则返回 304 (NOT_MODIFIED)。
此策略节省网络带宽但不节省 CPU,因为必须为每个请求计算完整响应。前面描述的控制器级别的其他策略可以避免计算。
此过滤器有一个 writeWeakETag
参数,该参数将过滤器配置为写入类似于以下内容的弱 ETag:W"02a2d595e6ed9a0b24f027f2b63b134d6"
(如 RFC 7232 Section 2.3 (opens new window) 中所定义)。
为了支持异步请求 (opens new window),这个过滤器必须用 DispatcherType.ASYNC
映射,这样过滤器才能延迟并成功生成一个 ETag 到最后最后一次异步调度。如果使用 Spring Framework 的 AbstractAnnotationConfigDispatcherServletInitializer
,所有过滤器都会自动为所有调度类型注册。但是,如果通过 web.xml
或在 Spring Boot 中通过 FilterRegistrationBean
注册过滤器,请确保包含 DispatcherType.ASYNC
。
# 跨域过滤器
Spring MVC 通过控制器上的注解为 CORS 配置提供细粒度支持。但是,当与 Spring Security 一起使用时,建议依赖内置的 CorsFilter
,它必须在 Spring Security 的过滤器链之前订阅。