Path Matching

    Servlet API 将完整的请求路径暴露为 requestURI,并进一步将其细分为 contextPath、servletPath 和 pathInfo,其值因 Servlet 的映射方式而异。从这些输入中,Spring MVC 需要确定用于处理程序映射的查询路径,即 DispatcherServlet 本身的映射中的路径,不包括 contextPath 和任何 servletMapping 前缀(如果存在)。

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

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

    幸运的是,默认的 Servlet 映射 /是一个不错的选择。然而,仍然有一个问题,即 requestURI 需要被解码,以便能够与控制器映射进行比较。这也是不可取的,因为有可能对改变路径结构的保留字符进行解码。如果这些字符不被期望,那么你可以拒绝它们(就像 Spring Security HTTP 防火墙),或者你可以将 UrlPathHelper 配置为 urlDecode=false,但控制器映射需要与编码后的路径相匹配,这可能并不总是很好。此外,有时 DispatcherServlet 需要与另一个 Servlet 共享 URL 空间,可能需要按前缀进行映射。

    通过从 PathMatcher 切换到 5.3 或更高版本中提供的解析 PathPattern,上述问题可以得到更全面的解决,见 模式比较。AntPathMatcher 需要对查找路径进行解码或对控制器映射进行编码,与此不同的是,解析的 PathPattern 与称为 RequestPath 的路径解析表示相匹配,一次一个路径段。这允许对路径段的值进行单独解码和消毒,而不存在改变路径结构的风险。Parsed PathPattern 还支持使用 servletPath 的前缀映射,只要前缀保持简单,没有任何需要编码的字符。