路径匹配

Servlet API 将完整的请求路径暴露为 requestURI,并进一步将其细分为 contextPathservletPathpathInfo,它们的值根据 Servlet 的映射方式而异。Spring MVC 需要根据这些输入确定用于映射 handler 的查找路径,该路径应排除 contextPath 和任何适用的 servletMapping 前缀。

servletPathpathInfo 会被解码,这使得它们无法与完整的 requestURI 直接进行比较以派生查找路径,因此需要对 requestURI 进行解码。然而,这带来了自身的问题,因为路径可能包含编码的保留字符,例如 "/"";",它们在解码后会改变路径结构,这也会导致安全问题。此外,Servlet 容器可能会对 servletPath 进行不同程度的规范化,这使得执行针对 requestURIstartsWith 比较变得更加困难。

这就是为什么最好避免依赖附带基于前缀的 servletPath 映射类型的 servletPath。如果 DispatcherServlet 被映射为默认 Servlet(使用 "/")或未使用前缀(使用 "/*"),并且 Servlet 容器是 4.0+,那么 Spring MVC 能够检测到 Servlet 映射类型并完全避免使用 servletPathpathInfo。在 3.1 Servlet 容器上,假设使用相同的 Servlet 映射类型,可以通过在 MVC 配置中通过 路径匹配 提供 UrlPathHelper 并设置 alwaysUseFullPath=true 来实现等效效果。

幸运的是,默认的 Servlet 映射 "/" 是一个不错的选择。然而,仍然存在一个问题,即需要对 requestURI 进行解码才能与控制器映射进行比较。这再次是不可取的,因为它可能解码保留字符从而改变路径结构。如果不需要此类字符,则可以拒绝它们(例如 Spring Security HTTP 防火墙),或者可以将 UrlPathHelper 配置为 urlDecode=false,但这要求控制器映射必须与编码的路径匹配,这并非总是可行。此外,有时 DispatcherServlet 需要与另一个 Servlet 共享 URL 空间,并可能需要通过前缀进行映射。

使用 PathPatternParser 和解析后的模式可以解决上述问题,作为使用 AntPathMatcher 进行字符串路径匹配的替代方案。从 5.3 版本开始,PathPatternParser 已可在 Spring MVC 中使用,并从 6.0 版本开始默认启用。与需要解码查找路径或编码控制器映射的 AntPathMatcher 不同,解析后的 PathPattern 会与路径的解析表示形式(称为 RequestPath)进行匹配,每次匹配一个路径段。这允许单独解码和净化路径段值,而不会改变路径结构。解析后的 PathPattern 还支持使用 servletPath 前缀映射,只要使用了 Servlet 路径映射且前缀保持简单(即没有编码字符)。有关模式语法详细信息和比较,请参阅 模式比较