最近又偶遇一诡异棘手之问题!
一个用于获取公钥数据的接口,不定期偶尔频频出现“参数不存在”的问题!
一度怀疑这是前端的锅,虽然前端同学再三以人格担保!
经过非仔细观察,发现每每出现问题时,“再点一下就好了”!
错误信息简单明确,是大家熟知的参数缺失异常:Required request parameter 'xxx' for method parameter type String is not present
But why? what's wrong?
Anyway,这是再普通不过的一个GET接口!
作为专业人士,咱自不能流于表象,当寻根溯源,探寻问题背后之本质!唯有寻得问题背后之根由,方可得正确解决问题之道!
Well, firstly, let's look look, what the hell a http go?
抱着“大胆假设,小心求证”之精神,以“抽丝剥茧”之排除大法,when the 参数 lost?!
So,What's up?
种种迹象表明:问题当发生在服务内部而非外部网络或请求转发丢失!
进一步分析,发现在问题请求中request.queryString()正常,而request.getParameter()值却是没有获取到!
众所周知的,SpringBoot默认内置tomcat容器,SpringMVC则通过request.getParameter方法获取并绑定Controller接口参数!
因此,初步判断在tomcat获取parameter参数时出现了不明原因问题!
Well,parameter参数的获取过程是怎样的?
1、SpringBoot从request获取parameter参数
RequestParamMethodArgumentResolver#resolveName
2、tomcat封装解析参数
request通过Parameters获取parameter参数:
org.apache.catalina.connector.Request#getParameterValues
3、Parameters从queryString解析封装parameter参数
org.apache.tomcat.util.http.Parameters#handleQueryParameters
可以发现,参数在解析处理后会设置didQueryParameters参数为true,
4、请求处理结束,还原
tomcat机制:
连接器Connector通过Processor对应http请求进行响应处理!
Processor封装了request与response对象:在请求处理开始时进行初始化封装(仅封装参数属性,并不创建对象),请求处理完成后则进行释放重置(仅重置参数属性,并不销毁对象)!
本次问题的根本原因则在于线程中引用了request对象,并在线程中调用了request.getParameter()方法使参数属性didQuerParameter错误而导致http请求无法正确获取参数值!
测试验证问题,问题重现与预期一致!
修复线程中引用request相关代码,问题解决!
参考:spring boot偶发性丢失POST请求参数问题的解决 - checkboxMan的个人空间 - OSCHINA - 中文开源技术交流社区