在 Spring MVC 中使用 PathPattern 進行 URL 匹配

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

最近釋出的 Spring Framework 5.3 M1 公告中提到了“Spring MVC 提供了 PathPattern 解析,可實現高效的 URL 匹配”。本文將提供更多背景和細節來擴充套件這一點。

概述

在 Spring 應用中,AntPathMatcher 用於識別 Spring 配置中的類路徑、檔案系統、遠端和其他資源。它也曾用於 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 benchmark 顯示吞吐量提高了 6-8 倍,分配率降低了 30-40%。您可以根據您的應用程式量身定製基準測試以獲得更準確的數字。

PathPatternAntPathMatcher 語法相容,但以下幾點除外:

  1. 支援附加語法來匹配和捕獲末尾的 0 個或多個路徑段,例如 "/foo/{*spring}"。這在 REST API 中非常有用,可以作為一種萬用字元模式,並透過 @PathVariable 訪問捕獲的路徑段。

  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 都獨立進行匹配,但其他元件(如攔截器)需要能夠支援和使用已解析的 PathPatternRequestPathAntPathMatcher 的 String lookupPath,具體取決於哪一個可用。

這就是為什麼從 5.3 開始,此類元件會使用 ServletRequestPathUtils 來檢查可用性,並相應地使用 PathPatternAntPathMatcher。大多數情況下,應用程式不需要擔心這一點,並且模式語法在很大程度上是相同的,因此應該可以正常工作。

字尾模式匹配

另外,在 5.3 版本中,Spring MVC 中使用字尾模式匹配以及其他透過路徑擴充套件進行內容協商的選項已預設關閉。多年來,這在許多方面被證明是存在問題的。這就是為什麼在使用 PathPatternParser 時不支援這一點的原因。即使使用 5.3 的 AntPathMatcher,如果您想繼續使用這些選項,也需要重新啟用它們。

總而言之,展望未來,我們期望 Spring MVC 應用程式切換到使用 PathPattern 而不是 AntPathMatcher,以利用效率提升、改進的語法以及更可預測的 URL 路徑處理方式。請嘗試使用 M1 版本,執行您的應用程式,或許可以進行基準測試,並告知我們您的反饋。

獲取 Spring 新聞通訊

透過 Spring 新聞通訊保持聯絡

訂閱

領先一步

VMware 提供培訓和認證,助您加速進步。

瞭解更多

獲得支援

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位制檔案,只需一份簡單的訂閱。

瞭解更多

即將舉行的活動

檢視 Spring 社群所有即將舉行的活動。

檢視所有