路徑比對
Servlet API 將完整請求路徑公開為 requestURI
,並進一步將其細分為 contextPath
、servletPath
和 pathInfo
,這些值會根據 Servlet 的對應方式而有所不同。Spring MVC 需要從這些輸入中,判斷用於對應處理常式的查找路徑,該路徑應排除 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
從 Spring MVC 5.3 版開始可用,並從 6.0 版開始預設啟用。與 AntPathMatcher
需要解碼查找路徑或編碼控制器對應不同,已解析的 PathPattern
會與路徑的已解析表示形式(稱為 RequestPath
)一次比對一個路徑段。這允許單獨解碼和清理路徑段值,而不會有改變路徑結構的風險。已解析的 PathPattern
也支援使用 servletPath
前綴對應,只要使用 Servlet 路徑對應且前綴保持簡單,即沒有編碼字元。有關模式語法詳細資訊和比較,請參閱模式比較。