Spring MVC 中使用 PathPattern 進行 URL 匹配

工程 | Rossen Stoyanchev | 2020 年 6 月 30 日 | ...

最近的 Spring Framework 5.3 M1 版本公告提到「Spring MVC 具有用於高效 URL 匹配的 PathPattern 解析」。 這篇文章將更詳細地闡述相關背景資訊。

概觀

在 Spring 應用程式中,AntPathMatcher 用於識別 Spring 配置中的 classpath、檔案系統、遠端和其他資源。 它也已在 Spring MVC 中用於匹配 URL 路徑。 隨著時間的推移,Web 應用程式中模式的使用數量和語法不斷增長,AntPathMatcher 不斷發展以滿足這些需求,但仍然存在一些問題,無法解決

  1. 在 Web 應用程式中,每個請求都需要多次匹配模式,因此效能和效率的任何提升都很重要。 然而,String 模式匹配限制了可以實現的目標。

  2. 多年來,在多個匹配請求的模式中選擇最特定的模式已被證明具有挑戰性,並且沒有簡單的方法可以在不影響其他情況的情況下使其更具可預測性。

  3. String 路徑與 String 模式進行匹配,使得避免 URI 編碼問題變得困難。 例如,是否應該先解碼傳入路徑,然後再進行匹配? 這允許在不使用編碼字元的情況下宣告模式本身,但如果請求路徑包含 %2F%3B,它們分別是 /; 怎麼辦? 一旦解碼,這些會改變路徑的結構,使其更難以可靠地匹配。 我們可以透過 UrlPathHelper#urlDecode 使請求路徑保持編碼狀態,但這樣我們就無法使用前綴 Servlet 映射,因為 servletPath 本身已解碼,並且我們的模式也需要編碼。

  4. 路徑參數提出了類似的挑戰。 它們可以在匹配之前移除,但如果我們想透過 @MatrixVariable 提取它們怎麼辦? 我們可以使用 UrlPathHelper#removeSemicolonContent 將它們保留在路徑中,但現在模式必須考慮路徑參數。

PathPattern

Spring Framework 5.0 中 Spring WebFlux 的引入是一個重新思考所有這些並創建替代方案的好機會。 這導致創建了已解析的 PathPattern,並針對表示 URL 路徑的已解析 PathContainer 進行匹配。

模式在啟動時解析,並在執行時重複使用,以實現高效的 URL 匹配。 效率有多高? 在沒有具體的用例的情況下,很難給出數字,但我們的 jmh 基準測試顯示吞吐量提高了 6-8 倍,分配率降低了 30-40%。 您可以調整基準測試,以獲得更準確的應用程式數字。

PathPatternAntPathMatcher 語法相容,但以下除外

  1. 支援其他語法,以匹配並捕獲結尾處的 0 個或多個路徑段,例如 "/foo/{*spring}"。 這在 REST API 中很有用,可以透過 @PathVariable 存取捕獲的路徑段,作為一個 catch-all 模式。

  2. 僅允許在模式的結尾處使用 "**" 進行多段匹配。 這有助於消除在為給定請求選擇最接近的匹配項時的大部分歧義。

PathContainer 有助於解決剩餘的問題。 例如,它從不解碼完整路徑,而是將其分解並單獨解碼路徑段,同時移除路徑參數,並將產生的解碼和正規化值一次匹配一個。 因此,編碼的 "/"";" 無法改變路徑的結構,並且路徑參數仍然可以保持可用。 這意味著無需配置如何解析請求路徑,並且無需考慮權衡取捨。

Spring MVC 與 PathPattern

從 Spring Framework 5.3 開始,Spring MVC 中支援使用 PathPattern,所有 HandlerMapping 實作都公開了一個屬性來設定 PathPatternParser,以替代使用 AntPathMatcher。 啟用此功能的最簡單方法是在 MVC 配置的路徑匹配選項中配置 PathPatternParser

反過來,如果 DispatcherServlet 檢測到任何已啟用已解析模式的 HandlerMapping,它會在執行時解析 URL 路徑,並使其在一個廣為人知的請求屬性下可用。 也可以使用 ServletRequestPathFilter 更早地完成此操作,在這種情況下,DispatcherServlet 將避免再次解析它。

PathPattern 和 AntPathMatcher 的混合使用

在某些情況下,可能有一個 HandlerMapping 啟用了已解析模式,而另一個使用 AntPathMatcher。 例如,第三方庫可能會註冊自己的 HandlerMapping bean,而未啟用已解析模式。 雖然每個 HandlerMapping 都獨立執行自己的匹配,但其他組件(如攔截器)需要能夠支援和使用已解析的 RequestPathPathPattern 或字串 lookupPathAntPathMatcher,具體取決於哪個可用。

這就是為什麼從 5.3 開始,此類組件使用 ServletRequestPathUtils 來檢查哪個可用,並相應地使用 PathPatternAntPathMatcher。 在大多數情況下,應用程式無需擔心這一點,並且模式語法基本相同,因此它的工作方式應該相同。

Suffix Pattern Matching(後綴模式匹配)

在相關說明中,在 5.3 中,Spring MVC 中使用後綴模式匹配以及透過路徑擴展進行內容協商的其他選項預設已關閉。 多年來,這在許多方面都被證明是有問題的。 這就是為什麼在使用 PathPatternParser 時甚至不支援這一點。 即使在 5.3 中使用 AntPathMatcher,如果您想繼續使用這些選項,也需要重新啟用它們。

總之,展望未來,我們希望 Spring MVC 應用程式切換為使用 PathPattern 而不是 AntPathMatcher,以利用效率提升、改進的語法以及更可預測的處理 URL 路徑問題的方式。 請嘗試在您自己的應用程式中使用 M1,也許可以透過基準測試來執行它,並讓我們知道任何回饋。

取得 Spring 電子報

隨時關注 Spring 電子報

訂閱

領先一步

VMware 提供培訓和認證,以加速您的進度。

了解更多

取得支援

Tanzu Spring 在一個簡單的訂閱中提供對 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位檔案。

了解更多

即將舉行的活動

查看 Spring 社群中所有即將舉行的活動。

檢視全部