路徑匹配

Servlet API 將完整的請求路徑暴露為 requestURI,並進一步將其細分為 contextPathservletPathpathInfo,它們的值根據 Servlet 的對映方式而異。Spring MVC 需要根據這些輸入確定用於對映 handler 的查詢路徑,該路徑應排除 contextPath 和任何適用的 servletMapping 字首。

servletPathpathInfo 會被解碼,這使得它們無法與完整的 requestURI 直接進行比較以派生查詢路徑,因此需要對 requestURI 進行解碼。然而,這帶來了自身的問題,因為路徑可能包含編碼的保留字元,例如 "/"";",它們在解碼後會改變路徑結構,這也會導致安全問題。此外,Servlet 容器可能會對 servletPath 進行不同程度的規範化,這使得執行針對 requestURIstartsWith 比較變得更加困難。

這就是為什麼最好避免依賴附帶基於字首的 servletPath 對映型別的 servletPath。如果 DispatcherServlet 被對映為預設 Servlet(使用 "/")或未使用字首(使用 "/*"),並且 Servlet 容器是 4.0+,那麼 Spring MVC 能夠檢測到 Servlet 對映型別並完全避免使用 servletPathpathInfo。在 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 路徑對映且字首保持簡單(即沒有編碼字元)。有關模式語法詳細資訊和比較,請參閱 模式比較