籠子大了什么鳥都有。同樣的道理,不論多么細心地設計 URI 結構,在系統(tǒng)復雜到一定程度后,仍然難以避免路徑?jīng)_突。為此,JAX-RS 使用一些規(guī)則來定義路徑匹配的優(yōu)先級。
如果某個請求路徑可以對上多個 URI 匹配模式,那么 JAX-RS 就把可能匹配上的 URI 模式先拼接完整,按照下列規(guī)則依次進行比較,直到找出最適合的匹配模式:
- 首先,字面字符數(shù)量更多的 URI 模式優(yōu)先。“字面字符”就是寫死的路徑段,不包含路徑分隔符
/
和模板參數(shù)。例如 /ms/rest/movie/{id : \\d+}
包含 11 個字面字符。
- 其次,模板參數(shù)個數(shù)最多的 URI 模式優(yōu)先。例如
/ms/rest/movie/{id : \\d+}
帶一個模板參數(shù)。
- 最后,含正則表達式的模板參數(shù)個數(shù)最多的 URI 模式優(yōu)先。例如
/ms/rest/movie/{id : \\d+}
帶一個含正則表達式的模板參數(shù)。
現(xiàn)在看一個例子。回顧一下,/ms/rest/movie/{id : \\d+}
已經(jīng)用來根據(jù) ID 獲取電影信息。為了制造麻煩,現(xiàn)在引入 /ms/rest/movie/{title}
來根據(jù)電影標題獲取電影信息。先請你猜一猜 /ms/rest/movie/300
代表啥?ID 為 300 的神秘電影,還是我們可愛的勇士?只能跟著規(guī)則一條一條地看:
- 首先,兩個 URI 匹配模式的字面字符都是 11,下一步。
- 其次,兩個 URI 匹配模式都帶一個模板參數(shù),下一步。
- 最后,只有
/ms/rest/movie/{id : \\d+}
帶了一個含正則表達式的模板參數(shù),勝利!所以返回 ID 為 300 的片片。
傳說這三條規(guī)則能夠覆蓋 90% 以上的情景。不過我們馬上就能造出一個打破規(guī)則的東西:/ms/rest/movie/{title : [ \\w]+}
。經(jīng)過測試,/ms/rest/movie/300
會匹配上 /ms/rest/movie/{id : \\d+}
。如何解釋?JAX-RS 規(guī)范文檔 3.7.2 定義了完整的匹配規(guī)則,對于這兩個簡單的 URI 匹配模式,似乎一直進行到底都無法比較出優(yōu)先級。莫非有另外的潛規(guī)則?或者是 JAX-RS 的實現(xiàn)(參考實現(xiàn)為 Jersey)自行規(guī)定?但無論如何,搞出這種怪物本身就是一個設計錯誤,所以也不必去深究原因。