- 现象
请求一个接口,post上来的数据保存到数据库中出现中文乱码
原因
2.1 做优雅停机时,增加了一个Filter,HttpRequestCounterFilter用来在记录机器当前正在处理的请求,在Filter的处理逻辑中调用了HttpRequest的getParameterMap()方法,第一次调用该方法时,request会去解析用户传入的参数,解析结果会被缓存下来,后续不会再重新解析。
从上图中可以看到,请求的参数只在第一次调用getParameterMap时被解析,解析结果保存在paramterMap中2.2 参数解析时的编码
解析时会去获取字符编码,如果没有设置,则使用默认ISO-8859-1编码格式。到这里可以猜到,应该是在新的filter调用getParamterMap()之前没有设置字符编码的问题。2.3 filter chain
tomcat初始化时,所有执行的filter链,HttpRequestCounterFilter是处于第二个filter,执行之前并没有设置编码,默认采用ISO-8859-1编码,所以HttpRequestCounterFilter中调用request.getParameterMap解析时出现乱码。
为什么去掉HttpRequestCounterFilter就正常了?
filter chain中有一个SetCharacterEncodingFilter会设置编码为UTF-8, 而在SetCharacterEncodingFilter之前是没有调用request.getParameterMap函数,所以并没有执行参数解析,参数解析是在Spring MVC中调用request.getParameterMap时完成。
SetCharacterEncodingFilter是tomcat web.xml配置的编码设置filter,tomcat启动加载应用时,会优先加载应用的web.xml, 然后再加载tomcat的web.xml。解决
应该在所有filter执行前设置编码,<filter> <filter-name>CharacterEncodingFilter</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> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
总结
(1). 在SpringMVC项目中应该首先在web.xml中配置CharacterEncodingFilter,处理编码问题
(2). 在pom.xml中添加如下依赖,调试tomcat源码
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>8.0.35</version>
</dependency>