当前位置: 首页 > 科技观察

因为滥用@PathVariable导致的bug,开发同学又被骂了

时间:2023-03-17 01:47:57 科技观察

前言最近测试同学反馈上周上线的一个功能偶尔会报404,按理说这个功能通过了测试在测试环境,也是在线运行了几天,为什么突然报错了?一开始以为是前端同学请求的接口不对,但是测试说只是意外的404,概率不高,于是打开日志找到对应的接口,看到了一看接口上定义的@PathVariable,再看参数,基本上肯定是开发者为了偷懒误用了@PathVariable造成的。先说结论:@PathVariable可以将请求参数动态绑定到URL上,但是如果请求参数中包含特殊字符,比如/,可能会导致Spring匹配到错误的URL,或者匹配不到合适的URL。重现下面,我将用一个简单的伪代码重现这个bug,和大家一起分析这个bug产生的原因,以及如何解决,最后顺便通过源码加深一下印象。如下,我们定义一个接口,通过@PathVariable将输入参数动态绑定到URL。@RestController@RequestMapping(value="/demo")publicclassDemoController{@GetMapping(value="/getVal/{val}")publicResponseEntitygetVal(@PathVariableStringval){System.out.println("参数:"+val);返回ResponseEntity.ok(val);然后我们测试这个接口:正常情况下,我们输入一个没有特殊符号的普通参数,控制台成功打印出来。但是,业务参数通常是不可控的。比如当参数变成“hello/world”时,代码就不能正常执行了。从图中可以看出,Spring将原本期望的URL:/demo/getVal/{val}解析为/demo/getVal/hello/world。测试同学之所以最近才发现这个界面有问题,正是因为没有遇到行首带/的参数,所以界面看起来很正常。直到最近在生产环境中遇到了带/的参数。正确的做法是:将URL定义为/demo/getVal,然后通过表单或查询来传递参数。解决方法很简单,相信有一定经验的同学可以很快解决这个问题。但是知道它,你需要知道为什么。带着这个问题,我们来探讨一下Spring是如何解析URL的。首先,我们找到Spring的webmvc包,找到org.springframework.web.servlet.handler包下的AbstractHandlerMethodMapping类。此类将绑定我们定义的映射与URL。该类中的lookupHandlerMethod方法为当前请求查找最匹配的handler方法,如果找到多个匹配,则选择最匹配的。分析这个方法,我们可以得到如下三个匹配步骤:1.根据Path进行精准匹配2.如果精准匹配不成功,开始模糊匹配3.如果模糊匹配还是失败,返回null至此,一个URL解析完毕过程结束。单看源码,可以发现其实逻辑并不复杂,就是一个不断按照规则匹配的过程。最后,一般来说,@PathVariable可以让我们在开发接口的时候省一些力气,但是需要注意的是,如果绑定的参数有特殊字符,可能会导致意想不到的bug。一般来说,@PathVariable更适合绑定整型参数。如果是字符串参数,建议还是通过form或者json传递参数。