|
对于最新稳定版本,请使用 Spring Framework 7.0.6! |
路径匹配
Servlet API 将完整的请求路径以 requestURI 的形式暴露出来,并进一步将其细分为 contextPath、servletPath 和 pathInfo,这些值会根据 Servlet 的映射方式而有所不同。基于这些输入,Spring MVC 需要确定用于映射处理器的查找路径(lookup path),该路径应排除 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 防火墙所做的那样),或者可以将 UrlPathHelper 配置为 urlDecode=false,但此时控制器映射必须与编码后的路径匹配,而这并不总能很好地工作。此外,有时 DispatcherServlet 需要与其他 Servlet 共享 URL 空间,因此可能需要通过前缀进行映射。
使用 PathPatternParser 和解析后的模式可以解决上述问题,以此作为使用 AntPathMatcher 进行字符串路径匹配的替代方案。PathPatternParser 自 5.3 版本起即可在 Spring MVC 中使用,并从 6.0 版本开始默认启用。与 AntPathMatcher 不同(后者需要对查找路径进行解码或对控制器映射进行编码),解析后的 PathPattern 会逐段匹配路径的解析表示形式(称为 RequestPath)。这使得能够单独对路径段值进行解码和清理,而不会改变路径结构的风险。解析后的 PathPattern 还支持使用 servletPath 前缀映射,前提是使用了 Servlet 路径映射且前缀保持简单(即不包含编码字符)。有关模式语法的详细信息及对比,请参阅 模式对比。