springboot升级过程中踩坑定位分析记录 | 京东云技术团队
作者:京东零售 李文龙
1.背景
“ 俗话说:为了修复一个小bug而引入了一个更大bug ”
因所负责的系统使用的spring框架版本5.1.5.RELEASE在线上出过一个偶发的小事故,最后定位为spring-context中的一个bug导致的。
为了修复此bug进行了spring版本的升级,最终定的版本为收银台团队使用的版本5.2.12.RELEASE,对应的springboot版本为2.2.12.RELEASE。
选择这个版本的原因是:
1.有团队经过了长时间的线上验证
2.修复了5.1.5.RELEASE对应的bug
2.升级上线
升级相关版本后在预发环境进行了验证,暂未遇到关于框架的问题。本以为安全升级完成,在上线过程中发现在APP中无法访问,此时还未挂载流量。
日志中分析是某些参数未解析到,后在nginx日志中查到相关请求,使用postman模拟请求可以正常使用。
3.分析验证定位原因
1.临时修复
在代码一致的情况下,唯一的可能就只能是线上与预发配置不同,经对比分析得出是某个过滤器的顺序在线上未配置,按照预发的配置后可正常使用。我们暂且称修改的这两个过滤器为M和A,
其中默认情况下执行顺序为M->A,顺序修改为A->M后正常,其两者作用大致为:
M : 通用过滤器,解析url中的参数至parameterMap中,并初始化读取了body中的inputstream进行了byte数组的缓存,用于解决重复读取流问题 A: 特定处理器,先是查询parameter中的参数,然后逻辑处理后再设置一些特殊参数。
2.为何需要改过滤器顺序
经查未升级前过滤器的顺序与升级后过滤器顺序一致,为何升级spring框架后需要修改配置。此时猜测可能是spring在升级过程中修改了一部分代码,
但未有头绪,只能先调转方向分析为什么postman和浏览器中的swagger可以正常使用
3.分析nginx日志
前端请求与postman请求的nginx日志进行了分析得出了原因,对比日志如下:
postman : POST /shop/bpaas/floor?client&clientVersion&ip=111.202.149.19&gfid=getShopMainFloor&body= 前端 : POST /shop/bpaas/floor HTTP/1.0" 200 634 "-" "api" "0.94" 0.008 0.007 client&clientVersion&ip=111.202.149.17&gfid=getShopMainFloor&body=
经过以上对比发现虽然postman使用了post请求,但数据还是放置在url中,在经过系统的一个内置过滤器M时将url中的参数解析到了parameterMap中,后续过滤器可以使用
request.getParameter获取到,注意此方法是解决问题的关键,此时还未意识到。
4.升级前后框架是否有大的修改
因升级的版本是升级了一个小版本号,所以不好对比升级的buglist,只能慢慢进行分析,后在分析过滤器时发现升级spring后过滤器个数由11个减少到了10个,减少了那一个为:
org.springframework.web.filter.HiddenHttpMethodFilter
此过虑器的作用是在浏览器不支持PUT、DELETE、PATCH等method时,可以在form表单中使用隐藏的_method参数支持这几种method。好像跟参数解析没有任何关系,
继续分析升级版本中 (由2.1.3.RELEASE->2.2.12.RELEASE)是否修改了此过滤器的一些内容,后在2.2.0.M5的release notes中发现HiddenHttpMethodFilter相关的:
“ Disable auto-configuration of HiddenHttpMethodFilter by default ” github上对应的版本release notes: https://github.com/spring-projects/spring-boot/releases/tag/v2.2.0.M5
也就是说升级后HiddenHttpMethodFilter默认配置由enable修改为了disable,如果再修改回去是不是可以修复参数解析的问题呢?
5.添加过滤器enable配置
因bug修复列表中有对应的issues,所以找到了此过滤器对应的配置:
-Dspring.mvc.hiddenmethod.filter.enabled=true
添加后可以正常使用,证明是此过滤器中在某种条件下不可缺少。
6.未升级spring版本时disable验证
在确认未升级版本的spring支持此参数的情况下,添加了以上参数,将默认的启动修改成了禁用,经验证:在不代码修改的情况下,无此过滤器时参数无法解析。证明了上步的猜测。
7.深入源码分析
此时需要分析HiddenHttpMethodFilter过滤器中是否有特殊操作,源码如下:
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { HttpServletRequest requestToUse = request; if ("POST".equals(request.getMethod()) && request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) { String paramValue = request.getParameter(this.methodParam); if (StringUtils.hasLength(paramValue)) { String method = paramValue.toUpperCase(Locale.ENGLISH); if (ALLOWED_METHODS.contains(method)) { requestToUse = new HttpMethodRequestWrapper(request, method); } } } filterChain.doFilter(requestToUse, response); }
分析以上源码可以发现,有且只有一种可能,就是request.getParameter可能是解决问题的是关键。
8.大胆猜测
分析后源码猜测,第一步中的修改顺序有可能是A中有调用getParameter,所以顺序调整为A->M后,相当于间接使用了HiddenHttpMethodFilter。
9.开始验证
在不使用HiddenHttpMethodFilter的情况下,如果在过滤器原有顺序不修改的情况下,只要在M执行前调用了request.getParameter,理论上可以正常为使用。所以在debug情况下
利用工具在M过滤器调用前先行执行request.getParameter,发现的确可以正常使用。
10.分析过滤器
先前简述了M的功能,主要是包装了request,后读源码时发现,如果是post请求,读取body体中的数据后并未解析body中的参数至parameterMap中,而代码中的其它过滤器都是
通过request.getParameter获取的数据,重写后的代码:
public String getParameter(String name) { if ( this.parameterMap.containsKey(name) ) return this.parameterMap.get(name); else { return super.getParameter(name); } }
在经过request包装后,先是从paremeterMap中获取数据,此时map肯定是没有数据,只能从父类获取,而父类获取时会解析parameter,解析时使用到了inputStream,但M过滤器
的在初始化时解析了输入流,此时tomcat内部使用内部的request获取stream时将获取到空数据,即无法从parameter中获取到body体中的数据。
而如果在调用M前调用了request.getParameter,tomcat内部将提前于M解析parameter,可以保证后续可获取到相关参数。
4. 修复方案
既然得出了结论,那么升级spring版本后修复此bug可选择的方案就比较多了,主要有:
此文是笔者按照分析流程进行简单验证,分析验证过程中难免有遗漏之处,如有错误遗漏还烦请各位指出共同进步。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
人类 vs AI:玩梗大作战,看看谁是最后的赢家?
能解释人类玩梗的 AI 究竟能多大程度地理解人类的「梗」? 五一假期就在眼前,LigaAI 小编每天都在「调休好烦」和「快放假啦」两种情绪间反复横跳,还会忍不住思考「AI 能不能理解调休和放假的情绪差异?」(一些精神世界高危的信号……) 早在今年三月,在 OpenAI 宣布 GPT-4 大模型可以接受文本和图像形式的 prompt 并理解人类玩梗后,我一直很好奇,AI 到底能多大程度地理解那些不断被创造出来的新梗、热梗(以及破梗)? (GPT-4:他用 VGA 线充 iPhone。) 它清楚「你已经是一个成熟的 AI 了」是什么意思吗?它知道「耗子喂汁」「夺笋啊」的正确打开方式吗?以及,它追热点的速度能赶得上我吗? 为了解开这些谜题(捍卫十级冲浪选手的尊严),LigaAI 借「五一出游」的热度,对 ChatGPT、GPT-4 和文心一言等大模型展开了测评。我们一起看看在「玩梗」这件事上,究竟谁更胜一筹? 01 我会发疯,AI 会吗? 在一众互联网文化中,「发疯文学」以混乱的语序、浓烈的情绪和不存在的逻辑,引得大家争相复制模仿,制造了一轮又一轮精神污染。尤其最近不少朋友纷纷表示,发现「周...
- 下一篇
从不均匀性角度浅析AB实验 | 京东云技术团队
作者:京东零售 路卫强 本篇的目的是从三个不均匀性的角度,对AB实验进行一个认知的普及,最终着重讲述AB实验的一个普遍的问题,即实验准确度问题。 一、AB实验场景 在首页中,我们是用红色基调还是绿色基调,是采用门店小列表外+商品feed(左图),还是采用门店大列表囊括商品feed(右图),哪种更吸引用户浏览下单呢,简单来处理让50%的用户看到左图效果,让50%的用户看到右图效果,最终通过点击量,单量等指标进行比对得出结论,这是典型的AB实验场景 二、AB实验的定义 A/B实验就是针对想迭代的产品功能,提供两种不同的备选解决方案,然后让一部分用户使用方案A,另一部分用户使用方案B,最终通过实验数据对比来确定最优方案。 从定义里我们就可以看出来,最直观的一个概念,就是用户的分流,此时就涉及到分流人数是否均匀的问题,即人数比例的均匀性。 三、AB中的三个不均匀 1、人数比例的不均匀 目前AB实验的分流核心算法是通过的哈希算法,假设我们按用户名做为分流因子,使用murmurhash算法,以100桶制为例,确定一个人的位置的算法就是 //将用户名通过hash算法计算出一个整数 int hashN...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Red5直播服务器,属于Java语言的直播服务器
- CentOS7,8上快速安装Gitea,搭建Git服务器
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- SpringBoot2全家桶,快速入门学习开发网站教程
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- CentOS8编译安装MySQL8.0.19