路径匹配

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

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

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

幸运的是,默认的 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 路径映射并且前缀保持简单,即它没有编码字符。有关模式语法详细信息和比较,请参阅 模式比较