Path Matching
Servlet API 将完整的请求路径公开为 requestURI
,并将其进一步细分为 contextPath
、servletPath
和 pathInfo
,其值因 Servlet 的映射方式而异。基于这些输入,Spring MVC 需要确定用于映射处理程序的查找路径,此路径应排除 contextPath
和任何 servletMapping
前缀(如果适用)。
The Servlet API exposes the full request path as requestURI
and further sub-divides it
into contextPath
, servletPath
, and pathInfo
whose values vary depending on how a
Servlet is mapped. From these inputs, Spring MVC needs to determine the lookup path to
use for mapping handlers, which should exclude the contextPath
and any servletMapping
prefix, if applicable.
servletPath
和 pathInfo
已解码,这使得无法直接与完整的 requestURI
进行比较以导出 lookupPath,并且必须对 requestURI
进行解码。然而,这引入了它自身的问题,因为路径可能包含编码的保留字符(如 "/"
或 ";"
),而这些字符在解码后可能依次更改路径的结构,也可能导致安全问题。此外,Servlet 容器可能会在不同程度上对 servletPath
进行规范化,这使得无法对 requestURI
执行 startsWith
比较。
The servletPath
and pathInfo
are decoded and that makes them impossible to compare
directly to the full requestURI
in order to derive the lookupPath and that makes it
necessary to decode the requestURI
. However this introduces its own issues because the
path may contain encoded reserved characters such as "/"
or ";"
that can in turn
alter the structure of the path after they are decoded which can also lead to security
issues. In addition, Servlet containers may normalize the servletPath
to varying
degrees which makes it further impossible to perform startsWith
comparisons against
the requestURI
.
这就是最好避免依赖于带有基于前缀 servletPath
映射类型的 servletPath
的原因。如果 DispatcherServlet
被映射为有 "/"
的默认 Servlet 或以其他方式映射为没有带有 "/*"
的前缀并且 Servlet 容器是 4.0 +,则 Spring MVC 能够检测 Servlet 映射类型并避免同时使用 servletPath
和 pathInfo
。在 3.1 Servlet 容器上,假设是相同的 Servlet 映射类型,可通过在 MVC 配置中通过 Path Matching 使用带有 alwaysUseFullPath=true
的 UrlPathHelper
来实现等效功能。
This is why it is best to avoid reliance on the servletPath
which comes with the
prefix-based servletPath
mapping type. If the DispatcherServlet
is mapped as the
default Servlet with "/"
or otherwise without a prefix with "/*"
and the Servlet
container is 4.0+ then Spring MVC is able to detect the Servlet mapping type and avoid
use of the servletPath
and pathInfo
altogether. On a 3.1 Servlet container,
assuming the same Servlet mapping types, the equivalent can be achieved by providing
a UrlPathHelper
with alwaysUseFullPath=true
via Path Matching in
the MVC config.
幸运的是,默认的 Servlet 映射 "/"
是一个不错的选择。然而,仍然存在一个问题,那就是需要对 requestURI
进行解码,以使其能够与控制器映射进行比较。由于可能会使更改路径结构的保留字符进行解码,因此这仍然不受欢迎。如果未预期此类字符,则可以拒绝它们(如 Spring Security HTTP 防火墙),或可以通过配置带有 urlDecode=false
的 UrlPathHelper
,但控制器映射需要与可能会不总是能很好工作的编码路径匹配。此外,有时 DispatcherServlet
需要与另一个 Servlet 共享 URL 空间,并且可能需要按前缀进行映射。
Fortunately the default Servlet mapping "/"
is a good choice. However, there is still
an issue in that the requestURI
needs to be decoded to make it possible to compare to
controller mappings. This is again undesirable because of the potential to decode
reserved characters that alter the path structure. If such characters are not expected,
then you can reject them (like the Spring Security HTTP firewall), or you can configure
UrlPathHelper
with urlDecode=false
but controller mappings will need to match to the
encoded path which may not always work well. Furthermore, sometimes the
DispatcherServlet
needs to share the URL space with another Servlet and may need to
be mapped by prefix.
在使用 PathPatternParser
和解析的模式时解决了上述问题,作为使用 AntPathMatcher
进行字符串路径匹配的替代方案。从版本 5.3 开始,PathPatternParser
已可用于 Spring MVC,并从版本 6.0 起默认启用。与需要对查找路径解码或对控制器映射进行编码的 AntPathMatcher
不同,解析的 PathPattern
一次一个路径片段地匹配到称为 RequestPath
的路径的解析表示。这允许分别解码和清理路径片段值,而无需冒改变路径结构的风险。解析的 PathPattern
还支持使用 servletPath
前缀映射,只要使用 Servlet 路径映射且前缀保持简单,即它没有编码字符。有关模式语法详细信息和比较,请参阅 Pattern Comparison。
The above issues are addressed when using PathPatternParser
and parsed patterns, as
an alternative to String path matching with AntPathMatcher
. The PathPatternParser
has
been available for use in Spring MVC from version 5.3, and is enabled by default from
version 6.0. Unlike AntPathMatcher
which needs either the lookup path decoded or the
controller mapping encoded, a parsed PathPattern
matches to a parsed representation
of the path called RequestPath
, one path segment at a time. This allows decoding and
sanitizing path segment values individually without the risk of altering the structure
of the path. Parsed PathPattern
also supports the use of servletPath
prefix mapping
as long as a Servlet path mapping is used and the prefix is kept simple, i.e. it has no
encoded characters. For pattern syntax details and comparison, see
Pattern Comparison.