Spring Boot REST端点匹配异常求助:带format参数仍匹配无format端点
Spring MVC路由匹配问题排查与解决
问题根源
- 路径变量贪婪匹配:第二个端点的路径
/record/{id}/{lcId}采用默认路径变量规则,会贪婪匹配路径末尾的所有内容,包括带点的字符串(比如2.json会被解析为lcId的值),导致带format的URL也能匹配到第二个端点。 - Headers匹配优先级干扰:第二个端点指定了
Accept头的匹配条件,当请求的Accept头符合该条件时,Spring会认为该端点的匹配度更高,进一步覆盖了路径的具体性优先级。
解决方案
方案一:约束第二个端点的路径变量格式
通过正则表达式限制lcId路径变量不能包含点,从根源上避免路径匹配歧义。修改第二个端点的路径定义:
@GetMapping(value = "/record/{id}/{lcId:[^.]+}", // 用正则约束lcId不含点 headers = {ACCEPT_HEADER_JSON, ACCEPT_HEADER_APPLICATION_RDF_XML, ACCEPT_HEADER_RDF_XML, ACCEPT_HEADER_APPLICATION_XML}, produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.TEXT_XML_VALUE, MediaType.APPLICATION_XML_VALUE, HttpHeaders.CONTENT_TYPE_APPLICATION_RDF_XML, HttpHeaders.CONTENT_TYPE_RDF_XML}) public ResponseEntity<String> getwithHeader( @PathVariable (value = "id") String id, @PathVariable (value = "lcId")String lcId, HttpServletRequest request) throws IOException { ... }
[^.]+表示匹配任意不含点的字符,这样带点的URL(如/record/1/2.json)只会匹配第一个端点,不带点的URL(如/record/1/2)则匹配第二个端点。
方案二:提升第一个端点的匹配优先级
如果不想修改路径规则,可以给第一个端点添加与第二个端点一致的headers条件,确保当路径和Headers都匹配时,更具体的路径端点优先:
@GetMapping(value = "/record/{id}/{lcId}.{format}", headers = {ACCEPT_HEADER_JSON, ACCEPT_HEADER_APPLICATION_RDF_XML, ACCEPT_HEADER_RDF_XML, ACCEPT_HEADER_APPLICATION_XML}, produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.TEXT_XML_VALUE, MediaType.APPLICATION_XML_VALUE, HttpHeaders.CONTENT_TYPE_APPLICATION_RDF_XML, HttpHeaders.CONTENT_TYPE_RDF_XML}) public ResponseEntity<String> getWithFormat( @PathVariable String id, @PathVariable String lcId, @PathVariable (value = "format") String format, HttpServletRequest request) throws IOException { .... }
此时Spring会优先选择路径更具体的第一个端点,同时满足Headers匹配条件。
验证说明
- 访问
/record/1/2.json:会匹配第一个端点,format参数被正确解析为json - 访问
/record/1/2且携带符合要求的Accept头:匹配第二个端点 - 访问
/record/1/2但Accept头不符合:会返回406 Not Acceptable,符合预期
内容的提问来源于stack exchange,提问作者Watermelon
相关产品推荐
相关产品推荐

