前段时间某功能在测试机器上出现乱码,情况如下:

 
现象:
          调试搜索功能时,通过doGet方法提交到后台的中文参数在本地和开发测试机器上为乱码(Action层),在测试人员测试机器上为中文.(Action层)
推断:
怀疑是两台机器(开发人员测试机器,测试人员测试机器)环境不同:
1. 先从tomcat查起,在他们各自的tomcat的配置文件server.xml中的Connector标签,有句指定URL编码的配置:URIEncoding="UTF-8" ,
    开发测试机器上没有配置(默认是IDO-8859-1),测试人员测试机器上配置为GBK,两个配置不同,改成一致(默认),再验证,还是存在乱码;
 
2. 怀疑是系统字符集的问题,用locale命令和查看/etc/sysconfig/i18n 文件查看两台机器的字符集,查看后发现两台机器系统字符集一致,都为UTF-8
 
3. 怀疑是apache上有不同的设置,再到apache的httpd.conf上查看,两天的设置基本一致,没有对编码有特殊的设置.
 
4. 怀疑是JVM运行参数的原因.java有一个运行时参数叫做:file.edcoding.这个编码是保存java文件的编码字符集,在调用javac.exe时,JDK用file.edcoding将.java文件
    读进来,转化为UNICODE放到内存中,所以,这个参数对乱码不会产生影响.
 
从以上可以看出,常规的排查手段已经不能找到原因,所以,从HTTP通信开始下手,从请求发起开始一步步排查,
首先,在本地,用到了3个工具,分别是:
     1. httpFox , Firefox上的一个插件,用来查看所有发起的http请求,内容非常详细.
     2. membrane-monitor 也是查看http通信的客户端,不依赖浏览器.
     3. Wireshark 同样是http的抓包工具,他不仅仅可以自己通过各种表达式抓取特定http包,还可以解析tcpdump(后面会说到)抓取的信息(好像tcpdump抓取的是16进制的数据)
 
这次排查三种工具都用到,最简单的是httpFox 使用简单,该有的功能都有,其次是Wireshark,还有很多功能没用到,感觉很强大,而且关键是和浏览器无关,是个很好的分析工具.
 
排查在两个浏览器中进行,IE9和Firefox17,在Firefox下可以看到用DoGET的方式带中文参数请求:

 
 Wireshark 抓取到的信息如下,是UTF-8编码的信息,这步是浏览器自己做的:

 
 在IE9下可以看到用DoGET的方式带中文参数请求:

 
 Wireshark 抓取到的信息如下,是UTF-8编码的信息,这步是浏览器自己做的:

  
从这里可以看到两个浏览发送中文参数请求的编码方式是不同的.请注意IE里面的高级设置中有这么一个选项:
经过试验这的URF8编码,是对URL中的中文例如:

www.baidu.com/中文/index.html 中的中文二字进行编码

发送请求后用Wireshark 可以看到,如下图,编码后的部分URL

 
为了验证,我在服务器上(开发人员测试机器)上又装上了服务器端的http抓包工具,tcpdump,安装过程如下:
1、打开网址:www.tcpdump.org/ 下载 libpcap-1.0.0.tar.gz (595.0KB) 软件包,通过命令 tar zxvf libpcap-1.0.0.tar.gz 解压文件,并将其放入自定义的安装目录。
2、打开网址:www.tcpdump.org/ 下载tcpdump-4.3.0.tar.gz (867.0KB) 软件包,通过命令 tar zxvf tcpdump-4.3.0.tar.gz 解压文件,并将其放入自定义的安装目录。
3.一次到解压目录下:      

./configure

  make

  make install
即可安装.
 
接着使用命令,将抓取到的信息放到write.log中,
 tcpdump -X -s 0  -w write.log   host xxx.xxx.xxx.xxx  and port 80
 
说明下参数:
     

-x  以16 进制数形式显示每一个报文

-s  重定义截取报文大小,默认为96(或68),如果定义为0,则表示获取完整报文

-w 将抓取到的报文放到文件中

host 指定抓取报文的目的地址

port  指定报文目的端口,因为该机器上是apache转发,填apache的端口就可以.

在服务端执行命令后用IE,Firefox下发送请求,将抓取到的文件放到Wireshark中解析,可以看到:

Firefox发送请求时服务端截取的文件:

IE9发送请求时服务端截取的文件:


 
可以看到和浏览器提交的编码是一致的,所以,可以推断,在浏览器端是编码传输的,并且没有产生所谓的乱码.
 
然后,我在服务端开启远程debug,可以看到在调用以下方法的时候产生了乱码:

 
但是仔细查看,发现request对象中有个specialAttribute属性,里面以键值对的方式存放了keyword参数,这里的keyword是上图中浏览器编码后的值,所以,在这里是没有乱码的。
 
为什么在调用request.getParameterMap()方法后会产生乱码呢? 
其实原因和tomcat有关系,在我们调用getParameterMap方法时,request对象会去找WEB容器中的URL编码去解码URL,在Tomcat中指的是在server.xml的以下配置中配置的编码

而开发人员测试机器上没有改配置,即默认使用ISO-8859-1去解码,测试人员测试机器上配置为GBK,即用GBK去解码URL,如果浏览器的编码和tomcat配置文件中配置的编码不一致,就会产生乱码 ,

为了证明我的猜想,我简单加密解密了一段中文,运行结果如下:

这里与我在debug过程中看到的乱码是一致,从而得出结论,乱码的根音来自于tomcat配置文件中设置的URLEncoding参数。

最后,再次总结下:

1. 采用DoGet方式传值,浏览器会帮我们编码,但是各个浏览器的编码方式不一致。

2. 传输过程中,编码后的值不会再被编码。

3. 通过Request对象取参数值时,Request对象会去Web容器中获取URL的编码方式,并用同样的编码区解码URL,如果浏览器的编码和Web容器中的编码不一致,就会产生乱码。

4. 解决方法,在浏览器提交请求前,将中文参数编码两次,浏览器不会再对其进行编码,传到服务端后解码一次即可。

为什么客户端编码两次,服务端解码一次?请看下图:

先声明一个被两次编码以后的字符串,模拟我在浏览器端手动编码的结果,

然后用三种方法对该字符串解码,为什么用三种? 因为这次解码是在调用request.getParameter时

request对象的解码服务端tomcat容器的URLEcoding可能是三种中的一种,可以看到无论是

什么编码方式的解码结果都是一样的,因为这里的配置可能是不一样的,所以要考虑到各种编码方式的可能,这个时候,我们再用代码手动解码一次,就可还原回中文了!

乱码问题就这么解决了,虽然需要手动的解码一次,不过我觉得这个值得,因为乱码后的情况奇奇怪怪,

若觉得每次接么复杂,只需在拦截器端都统一解码就可以,以后不用再担心这个问题.

 

最新文章

  1. 【CSS进阶】试试酷炫的 3D 视角
  2. 关于在gridview中有dorpdownlist的情况下使用自带编辑模板的方法
  3. 【转】JSP中的相对路径和绝对路径
  4. uva 10065 (凸包+求面积)
  5. javascript多重继承
  6. 小课堂Week11 会说话的代码
  7. POJ1062 昂贵的聘礼 【DFS】
  8. java中int,float,long,double取值范围,内存泄露
  9. MATLAB下跑Faster-RCNN+ZF实验时如何编译自己需要的external文件
  10. Mybatis框架解析之Builder解析
  11. 阿里云服务器部署php的laravel项目,在阿里云买ECS 搭建 Linux+Nginx+Mysql+PHP环境的
  12. Spring AOP 的proxy详解
  13. 小程序-camera
  14. MISCONF Redis is configured to save RDB snapshots, but it is currently not able to persist on disk. Commands that may modify the data set are disabled, because this instance is configured to report e
  15. 17.1-uC/OS-III消息管理(两种消息队列)
  16. Spring容器是如何实现 Bean 自动注入(xml)
  17. C++ 单例模式(转载)
  18. elasticsearch安装与使用(6)-- Logstash安装与配置
  19. 课下实践——实现Mypwd
  20. React 16 源码瞎几把解读 【二】 react组件的解析过程

热门文章

  1. 【BZOJ4723】[POI2017]Flappy Bird DP
  2. 在java中public void与public static void有什么区别 ?
  3. PAT 1013 Battle Over Cities(并查集)
  4. Xenu Link Sleuth
  5. php 正则表达式一.函数解析
  6. <2014 04 15> C++语言回顾精要(原创By Andrew)
  7. python系列十七:Python3 标准库概览
  8. python类的相关知识第一部分
  9. Django框架-模板系统
  10. 用户登录失败,该用户与可信SQL Server连接无关联,错误:18452