此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 Spring Framework 6.2.10! |
过滤器
这spring-web
模块提供了一些有用的过滤器:
Servlet 过滤器可以在web.xml
配置文件或使用 Servlet 注释。
如果您使用的是 Spring Boot,则可以将它们声明为 bean 并将它们配置为应用程序的一部分。
表单数据
浏览器只能通过 HTTP GET 或 HTTP POST 提交表单数据,但非浏览器客户端也可以
使用 HTTP PUT、PATCH 和 DELETE。Servlet API 需要ServletRequest.getParameter*()
仅支持对 HTTP POST 进行表单字段访问的方法。
这spring-web
模块提供FormContentFilter
拦截 HTTP PUT、PATCH 和 DELETE
内容类型为application/x-www-form-urlencoded
,从
请求的正文,并将ServletRequest
制作表单数据
可通过ServletRequest.getParameter*()
方法系列。
请求头转发
当请求通过代理(例如负载均衡器)时,主机、端口和 方案可能会发生变化,这使得创建指向正确链接成为一项挑战 从客户端的角度来看,主机、端口和方案。
RFC 7239 定义了Forwarded
HTTP 标头
代理可以使用该信息来提供有关原始请求的信息。
非标准标头
还有其他非标准标头,包括X-Forwarded-Host
,X-Forwarded-Port
,X-Forwarded-Proto
,X-Forwarded-Ssl
和X-Forwarded-Prefix
.
X转发主机
虽然不是标准的,X-Forwarded-Host: <host>
是一个事实上的标准标头,用于将原始主机传达给
下游服务器。例如,如果请求example.com/resource
被发送到
将请求转发给localhost:8080/resource
,然后是X-Forwarded-Host: example.com
可以发送以通知服务器原始主机是example.com
.
X转发端口
虽然不是标准的,X-Forwarded-Port: <port>
是一个事实上的标准标头,用于
将原始端口通信到下游服务器。例如,如果请求example.com/resource
被发送到代理,代理将请求转发给localhost:8080/resource
,然后是X-Forwarded-Port: 443
可以发送
通知服务器原始端口是443
.
X-转发-原型
虽然不是标准的,X-Forwarded-Proto: (https|http)
是用于通信原始协议(例如,https / http)的事实上的标准标头
到下游服务器。例如,如果请求example.com/resource
被发送到
将请求转发给localhost:8080/resource
,然后是X-Forwarded-Proto: https
可以发送以通知服务器原始协议是https
.
X-转发-SSL
虽然不是标准的,X-Forwarded-Ssl: (on|off)
是一个事实上的标准标头,用于传达
原始协议(例如,HTTPS/HTTPS)发送到下游服务器。例如,如果请求example.com/resource
被发送到代理,代理将请求转发给localhost:8080/resource
,然后是X-Forwarded-Ssl: on
通知服务器
最初的协议是https
.
X转发前缀
虽然不是标准的,X-Forwarded-Prefix: <prefix>
是一个事实上的标准标头,用于将原始 URL 路径前缀传达给
下游服务器。
用途X-Forwarded-Prefix
可能因部署方案而异,并且需要灵活地
允许替换、删除或预置目标服务器的路径前缀。
方案 1:覆盖路径前缀
https://example.com/api/{path} -> http://localhost:8080/app1/{path}
前缀是捕获组之前路径的开头{path}
.对于代理,
前缀是/api
而对于服务器,前缀是/app1
.在这种情况下,代理
可以发送X-Forwarded-Prefix: /api
具有原始前缀/api
覆盖
服务器前缀/app1
.
方案 2:删除路径前缀
有时,应用程序可能希望删除前缀。例如,考虑 以下代理到服务器的映射:
https://app1.example.com/{path} -> http://localhost:8080/app1/{path} https://app2.example.com/{path} -> http://localhost:8080/app2/{path}
代理没有前缀,而应用程序app1
和app2
有路径前缀/app1
和/app2
分别。代理可以发送X-Forwarded-Prefix:
自
让空前缀覆盖服务器前缀/app1
和/app2
.
此部署方案的一个常见情况是按按 生产应用程序服务器,最好在每个应用程序中部署多个应用程序 服务器以降低费用。另一个原因是在同一台服务器上运行更多应用程序 以共享服务器运行所需的资源。 在这些方案中,应用程序需要一个非空上下文根,因为有多个 同一服务器上的应用程序。但是,这在 公共 API,应用程序可以使用提供好处的不同子域 如:
|
方案 3:插入路径前缀
在其他情况下,可能需要在前面添加前缀。例如,考虑 以下代理到服务器的映射:
https://example.com/api/app1/{path} -> http://localhost:8080/app1/{path}
在这种情况下,代理的前缀为/api/app1
服务器的前缀为/app1
.代理可以发送X-Forwarded-Prefix: /api/app1
具有原始前缀/api/app1
覆盖服务器前缀/app1
.
转发标头过滤器
ForwardedHeaderFilter
是一个 Servlet 过滤器,用于修改请求以
a) 根据Forwarded
标头,b) 删除这些
标头以消除进一步的影响。过滤器依赖于包装请求,并且
因此,它必须先于其他过滤器(例如RequestContextFilter
那
应该使用修改后的请求,而不是原始请求。
安全注意事项
请求头转发存在安全注意事项,因为应用程序无法知道
如果标头是由代理按预期添加的,还是由恶意客户端添加的。这就是为什么
应配置信任边界处的代理以删除不受信任的Forwarded
来自外部的标题。您还可以配置ForwardedHeaderFilter
跟removeOnly=true
,在这种情况下,它会删除但不使用标头。
调度程序类型
为了支持异步请求和错误分派
filter 应映射为DispatcherType.ASYNC
还有DispatcherType.ERROR
.
如果使用 Spring Framework 的AbstractAnnotationConfigDispatcherServletInitializer
(参见 Servlet 配置)所有过滤器都会自动注册所有分派
类型。但是,如果通过web.xml
或在 Spring Boot 中通过FilterRegistrationBean
请务必包括DispatcherType.ASYNC
和DispatcherType.ERROR
除了DispatcherType.REQUEST
.
浅 ETag
这ShallowEtagHeaderFilter
filter 通过缓存内容创建“浅层”ETag
写入响应并从中计算 MD5 哈希值。下次客户端发送
它做同样的事情,但它也会将计算值与If-None-Match
request 标头,如果两者相等,则返回 304 (NOT_MODIFIED)。
此策略可节省网络带宽,但不会节省 CPU,因为必须为每个请求计算完整响应。
更改状态的 HTTP 方法和其他 HTTP 条件请求标头,例如If-Match
和If-Unmodified-Since
不在此过滤器的范围内。控制器级别的其他策略
可以避免计算,并对 HTTP 条件请求有更广泛的支持。
请参阅 HTTP 缓存。
此过滤器具有writeWeakETag
参数,用于将过滤器配置为写入弱 ETag
类似于以下内容:W/"02a2d595e6ed9a0b24f027f2b63b134d6"
(定义见 RFC 7232 第 2.3 节)。
为了支持异步请求,必须映射此过滤器
跟DispatcherType.ASYNC
以便过滤器可以延迟并成功生成
ETag 到最后一个异步调度的末尾。如果使用 Spring Framework 的AbstractAnnotationConfigDispatcherServletInitializer
(参见 Servlet 配置)
所有筛选器都会自动为所有调度类型注册。但是,如果注册
过滤器通过web.xml
或在 Spring Boot 中通过FilterRegistrationBean
请务必包括DispatcherType.ASYNC
.
CORS
Spring MVC 通过对 CORS 配置的注释提供细粒度的支持
控制器。但是,当与 Spring Security 一起使用时,我们建议依赖内置的CorsFilter
必须在 Spring Security 的过滤器链之前排序。
URL 处理程序
在以前的 Spring Framework 版本中,Spring MVC 可以配置为忽略 URL 路径中的尾随斜杠
在控制器方法上映射传入请求时。这意味着发送“GET /home/”请求将是
由用@GetMapping("/home")
.
此选项在 6.0 中已弃用,并在 7.0 中删除,但应用程序仍应处理此类
以安全的方式请求。这UrlHandlerFilter
Servlet 过滤器就是为此目的而设计的。
它可以配置为:
-
在收到带有尾随斜杠的 URL 时响应 HTTP 重定向状态,将浏览器发送到非尾随斜杠 URL 变体。
-
包装请求以执行请求,就像发送请求时不带尾随斜杠一样,并继续处理请求。
以下是如何实例化和配置UrlHandlerFilter
对于博客应用程序:
-
Java
-
Kotlin
UrlHandlerFilter urlHandlerFilter = UrlHandlerFilter
// will HTTP 308 redirect "/blog/my-blog-post/" -> "/blog/my-blog-post"
.trailingSlashHandler("/blog/**").redirect(HttpStatus.PERMANENT_REDIRECT)
// will wrap the request to "/admin/user/account/" and make it as "/admin/user/account"
.trailingSlashHandler("/admin/**").wrapRequest()
.build();
val urlHandlerFilter = UrlHandlerFilter
// will HTTP 308 redirect "/blog/my-blog-post/" -> "/blog/my-blog-post"
.trailingSlashHandler("/blog/**").redirect(HttpStatus.PERMANENT_REDIRECT)
// will wrap the request to "/admin/user/account/" and make it as "/admin/user/account"
.trailingSlashHandler("/admin/**").wrapRequest()
.build()