跳到主要内容

路径匹配

ChatGPT-4o-mini 中英对照 Path Matching

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

servletPathpathInfo 是被解码的,这使得它们无法直接与完整的 requestURI 进行比较以推导出 lookupPath,这使得解码 requestURI 成为必要。然而,这引入了自身的问题,因为路径可能包含编码的保留字符,例如 "/"";",这些字符在解码后可能会改变路径的结构,这也可能导致安全问题。此外,Servlet 容器可能会对 servletPath 进行不同程度的规范化,这使得进一步无法对 requestURI 进行 startsWith 比较。

这就是为什么最好避免依赖带有前缀的 servletPath 映射类型的 servletPath。如果 DispatcherServlet 被映射为默认 Servlet,使用 "/" 或者没有前缀的 "/*",并且 Servlet 容器是 4.0+,那么 Spring MVC 能够检测 Servlet 映射类型,并完全避免使用 servletPathpathInfo。在 3.1 Servlet 容器上,假设相同的 Servlet 映射类型,可以通过在 MVC 配置中提供 alwaysUseFullPath=trueUrlPathHelper 来实现等效功能,具体请参见 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