笼子大了什么鸟都有。同样的道理,不论多么细心地设计 URI 结构,在系统复杂到一定程度后,仍然难以避免路径冲突。为此,JAX-RS 使用一些规则来定义路径匹配的优先级。
如果某个请求路径可以对上多个 URI 匹配模式,那么 JAX-RS 就把可能匹配上的 URI 模式先拼接完整,按照下列规则依次进行比较,直到找出最适合的匹配模式:
- 首先,字面字符数量更多的 URI 模式优先。“字面字符”就是写死的路径段,不包含路径分隔符
/
和模板参数。例如 /ms/rest/movie/{id : \\d+}
包含 11 个字面字符。
- 其次,模板参数个数最多的 URI 模式优先。例如
/ms/rest/movie/{id : \\d+}
带一个模板参数。
- 最后,含正则表达式的模板参数个数最多的 URI 模式优先。例如
/ms/rest/movie/{id : \\d+}
带一个含正则表达式的模板参数。
现在看一个例子。回顾一下,/ms/rest/movie/{id : \\d+}
已经用来根据 ID 获取电影信息。为了制造麻烦,现在引入 /ms/rest/movie/{title}
来根据电影标题获取电影信息。先请你猜一猜 /ms/rest/movie/300
代表啥?ID 为 300 的神秘电影,还是我们可爱的勇士?只能跟着规则一条一条地看:
- 首先,两个 URI 匹配模式的字面字符都是 11,下一步。
- 其次,两个 URI 匹配模式都带一个模板参数,下一步。
- 最后,只有
/ms/rest/movie/{id : \\d+}
带了一个含正则表达式的模板参数,胜利!所以返回 ID 为 300 的片片。
传说这三条规则能够覆盖 90% 以上的情景。不过我们马上就能造出一个打破规则的东西:/ms/rest/movie/{title : [ \\w]+}
。经过测试,/ms/rest/movie/300
会匹配上 /ms/rest/movie/{id : \\d+}
。如何解释?JAX-RS 规范文档 3.7.2 定义了完整的匹配规则,对于这两个简单的 URI 匹配模式,似乎一直进行到底都无法比较出优先级。莫非有另外的潜规则?或者是 JAX-RS 的实现(参考实现为 Jersey)自行规定?但无论如何,搞出这种怪物本身就是一个设计错误,所以也不必去深究原因。