公司代码以前是前后端整合在一起的,由于要升级技术栈,现在做前后端分离。原本没有问题,前端童鞋拆分完后中文乱码的问题来了,一个导出的接口多个参数用的get请求,其中有个字段 产品名称 前端传中文到后台出现了中文乱码。
why? 询问前端同学改了什么字符集编码没?答:没有啊!
测试同学催的厉害,明天要上线了今晚必须结束测试(工期短,需求长啊)。奈何前端同学又回家了,作为后端的我只能硬着头皮去修改了,于是我尝试将其转码。
做了如下骚操作:
productName = productName == null ? null : new String(productName.getBytes("iso-8859-1"), "utf-8");
手动发布到开发环境验证,通过!
提交代码,走流水线(测试环境是不允许开发插手的)发布到测试环境,等待测试同学验证,通过!
测试同学高兴,前端同学高兴,我也高兴,问题“完美解决”。
第二天晚上上线,不输入产品名称可以导出。输入产品名称,无数据可导出!!!
扒开生产环境日志,心里很难受,为毛呢,生产环境日志数据级为info,在没有抛异常或错误的情况下,能看到的仅仅只有接口调用短短一两行日志。告诉自己冷静,仔细思考着为什么。这时我心里一咯噔,中文乱码!!!因为产品名称中文乱码,传输到后台执行sql后查询不到任何数据,因此返回:无数据可导出!虽然没有日志,但是凭借着经验,应该就是这个问题了。
但是话又说回来了,WTF!什么鬼啊这是!我明明做了转码了,开发、测试环境都可以,生产环境不行?
确认运维是否打了旧包,确认结果:版本无误,包没问题。这时候我已经把注意力转移到环境的问题上了。想到了我们运行的容器tomcat身上了。问了下运维生产环境tomcat版本号:tomcat 8.5.31
,至此问题已经基本找到了。再次确认下开发和测试环境tomcat版本号均为:7.0.77
,问题已经完全定位了:
tomcat 8 默认编码格式:utf-8, tomcat 7 默认编码格式:iso-8859-1。
恰巧因为文章开头我为了修复开发和测试环境的中文乱码问题做的一次后台转码才导致在生产环境上出现了乱码。OMG,宝宝心里苦,宝宝还想说出来呢。至此后续就是内部沟通、解释等事情了。
再把话题转回来,为什么get请求会出现中文乱码而post请求没事呢?
抱着刨根问底的心态继续探索:我们的项目在web.xml中用了filter:
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<async-supported>true</async-supported>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
既然用了filter为毛post请求可以get请求不行呢?搞歧视?
翻看CharacterEncodingFilter源码:
@Override
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
if (this.encoding != null && (this.forceEncoding || request.getCharacterEncoding() == null)) {
request.setCharacterEncoding(this.encoding);
if (this.forceEncoding) {
response.setCharacterEncoding(this.encoding);
}
}
filterChain.doFilter(request, response);
}
看了源码之后doFilterInternal方法仿佛给了我答案,原来过滤器是通过request.setCharacterEncoding(this.encoding);
方式来设置编码方式的。这种方式显然post请求提交的数据,是可以通过设置生效的。但是get请求提交的内容在url中,一开始就已经按照编码分析提交内容,因此request.setCharacterEncoding(this.encoding);
对其无效。
至此,疑惑已经基本解开完了,忙里偷闲记个笔记。告诫自己,帮助他人!
如文中出现错误或不准确的地方还请各位大佬不吝赐教,毕竟我菜啊(手动滑稽)!!!