路径匹配
Servlet API 将完整的请求路径暴露为 requestURI
,并进一步将其细分为 contextPath
、servletPath
和 pathInfo
,它们的值根据 Servlet 的映射方式而异。Spring MVC 需要从这些输入中确定用于映射处理程序的查找路径,该路径应排除 contextPath
和任何 servletMapping
前缀(如果适用)。
servletPath
和 pathInfo
是经过解码的,这使得它们无法直接与完整的 requestURI
进行比较以派生查找路径,因此有必要对 requestURI
进行解码。然而,这带来了它自己的问题,因为路径可能包含编码的保留字符,例如 "/"
或 ";"
,这些字符在解码后可能会改变路径的结构,从而导致安全问题。此外,Servlet 容器可能会在不同程度上对 servletPath
进行规范化,这使得对 requestURI
执行 startsWith
比较变得更加不可能。
这就是为什么最好避免依赖于带有基于前缀的 servletPath
映射类型的 servletPath
。如果 DispatcherServlet
被映射为默认的 Servlet,使用 "/"
或不带前缀的 "/*"
,并且 Servlet 容器是 4.0+,那么 Spring MVC 能够检测到 Servlet 映射类型并完全避免使用 servletPath
和 pathInfo
。在 3.1 Servlet 容器上,假设相同的 Servlet 映射类型,可以通过在 MVC 配置的 路径匹配 中提供一个带有 alwaysUseFullPath=true
的 UrlPathHelper
来实现相同的效果。
幸运的是,默认的 Servlet 映射 "/"
是一个不错的选择。然而,仍然存在一个问题,即 requestURI
需要解码才能与控制器映射进行比较。这又是不可取的,因为它可能会解码改变路径结构的保留字符。如果不需要此类字符,则可以拒绝它们(例如 Spring Security HTTP 防火墙),或者可以使用 urlDecode=false
配置 UrlPathHelper
,但控制器映射将需要与编码路径匹配,这可能并非总是有效。此外,有时 DispatcherServlet
需要与另一个 Servlet 共享 URL 空间,并且可能需要通过前缀进行映射。
当使用 PathPatternParser
和解析模式时,上述问题得到了解决,这是 AntPathMatcher
进行字符串路径匹配的替代方案。PathPatternParser
从 Spring MVC 5.3 版本开始可供使用,并从 6.0 版本开始默认启用。与 AntPathMatcher
需要解码查找路径或编码控制器映射不同,解析后的 PathPattern
一次匹配一个路径段,与路径的解析表示(称为 RequestPath
)匹配。这允许单独解码和清理路径段值,而不会有改变路径结构的风险。解析后的 PathPattern
还支持使用 servletPath
前缀映射,只要使用了 Servlet 路径映射并且前缀保持简单,即它没有编码字符。有关模式语法详细信息和比较,请参阅 模式比较。