路径匹配
Servlet API 将完整请求路径暴露为 requestURI
,并进一步将其细分为 contextPath
、servletPath
和 pathInfo
,其值取决于 Servlet 的映射方式。根据这些输入,Spring MVC 需要确定用于映射处理程序的查找路径,该路径应排除 contextPath
和任何 servletMapping
前缀(如果适用)。
servletPath
和 pathInfo
是被解码的,这使得它们无法直接与完整的 requestURI
进行比较以推导出 lookupPath,这使得解码 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
来实现等效功能,具体请参见 Path Matching。
幸运的是,默认的 Servlet 映射 "/"
是一个不错的选择。然而,仍然存在一个问题,即 requestURI
需要被解码,以便能够与控制器映射进行比较。这再次是不理想的,因为可能会解码保留字符,从而改变路径结构。如果不期望出现这样的字符,那么可以拒绝它们(就像 Spring Security HTTP 防火墙),或者可以将 UrlPathHelper
配置为 urlDecode=false
,但控制器映射需要与编码路径匹配,这可能并不总是有效。此外,有时 DispatcherServlet
需要与另一个 Servlet 共享 URL 空间,并可能需要通过前缀进行映射。
上述问题在使用 PathPatternParser
和解析后的模式时得到了处理,作为使用 AntPathMatcher
进行字符串路径匹配的替代方案。PathPatternParser
从版本 5.3 开始可用于 Spring MVC,并且从版本 6.0 开始默认启用。与需要解码查找路径或编码控制器映射的 AntPathMatcher
不同,解析后的 PathPattern
逐段匹配路径的解析表示,称为 RequestPath
。这允许单独解码和清理路径段值,而不必担心改变路径的结构。解析后的 PathPattern
还支持使用 servletPath
前缀映射,只要使用 Servlet 路径映射并且前缀保持简单,即没有编码字符。有关模式语法的详细信息和比较,请参见 Pattern Comparison。