路径匹配
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
来实现等效功能。
幸运的是,默认 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 路径映射并且前缀保持简单(即没有编码字符)。有关模式语法详细信息和比较,请参见 模式比较。