路徑匹配
Servlet API 將完整的請求路徑暴露為 requestURI
,並進一步將其細分為 contextPath
、servletPath
和 pathInfo
,它們的值根據 Servlet 的對映方式而異。Spring MVC 需要根據這些輸入確定用於對映 handler 的查詢路徑,該路徑應排除 contextPath
和任何適用的 servletMapping
字首。
servletPath
和 pathInfo
會被解碼,這使得它們無法與完整的 requestURI
直接進行比較以派生查詢路徑,因此需要對 requestURI
進行解碼。然而,這帶來了自身的問題,因為路徑可能包含編碼的保留字元,例如 "/"
或 ";"
,它們在解碼後會改變路徑結構,這也會導致安全問題。此外,Servlet 容器可能會對 servletPath
進行不同程度的規範化,這使得執行針對 requestURI
的 startsWith
比較變得更加困難。
這就是為什麼最好避免依賴附帶基於字首的 servletPath
對映型別的 servletPath
。如果 DispatcherServlet
被對映為預設 Servlet(使用 "/"
)或未使用字首(使用 "/*"
),並且 Servlet 容器是 4.0+,那麼 Spring MVC 能夠檢測到 Servlet 對映型別並完全避免使用 servletPath
和 pathInfo
。在 3.1 Servlet 容器上,假設使用相同的 Servlet 對映型別,可以透過在 MVC 配置中透過 路徑匹配 提供 UrlPathHelper
並設定 alwaysUseFullPath=true
來實現等效效果。
幸運的是,預設的 Servlet 對映 "/"
是一個不錯的選擇。然而,仍然存在一個問題,即需要對 requestURI
進行解碼才能與控制器對映進行比較。這再次是不可取的,因為它可能解碼保留字元從而改變路徑結構。如果不需要此類字元,則可以拒絕它們(例如 Spring Security HTTP 防火牆),或者可以將 UrlPathHelper
配置為 urlDecode=false
,但這要求控制器對映必須與編碼的路徑匹配,這並非總是可行。此外,有時 DispatcherServlet
需要與另一個 Servlet 共享 URL 空間,並可能需要透過字首進行對映。
使用 PathPatternParser
和解析後的模式可以解決上述問題,作為使用 AntPathMatcher
進行字串路徑匹配的替代方案。從 5.3 版本開始,PathPatternParser
已可在 Spring MVC 中使用,並從 6.0 版本開始預設啟用。與需要解碼查詢路徑或編碼控制器對映的 AntPathMatcher
不同,解析後的 PathPattern
會與路徑的解析表示形式(稱為 RequestPath
)進行匹配,每次匹配一個路徑段。這允許單獨解碼和淨化路徑段值,而不會改變路徑結構。解析後的 PathPattern
還支援使用 servletPath
字首對映,只要使用了 Servlet 路徑對映且字首保持簡單(即沒有編碼字元)。有關模式語法詳細資訊和比較,請參閱 模式比較。