1. 为什么会产生乱码?
因为浏览器不允许提交非ASCII字符,如果提交了非ASCII,则浏览器自动对其进行编码,将它们转换为ASCII字符。根据浏览器的不同,转换时使用的编码也不同,比如有些浏览器会使用utf-8进行编码,而有些会使用gbk进行编码。
2. 浏览器为什么不允许提交非ASCII字符?
以下是我个人观点,仅供参考。
因为浏览器和服务器通信,传输的都是字节。而我们在页面提交的都是字符,所以浏览器底层就有一个将字符转换为字节的过程,这个过程涉及到编码,浏览器到底是用utf-8、gbk还是iso-8859-1将字符转换为字节呢?我想应该是iso-8859-1,因为这是西欧默认使用的编码。何况,也没有任何理由使用前两种编码格式。但是iso-8859-1编码是不能识别中文以及其他非ASCII字符的,所以如果字符中存在这类字符,那么将字符转换为字节的过程中势必会产生乱码。为了避免这种情况的发生,浏览器自动对非ASCII字符进行了编码,将这类字符转换为ASCII字符,这样就能避免乱码问题。
3. GET和POST提交表单,分别根据什么对非ASCII字符进行编码?
GET:
情况比较复杂,不同浏览器也不一样,有的使用gbk,有的使用utf-8不好一概而论。
POST:
浏览器会根据网页编码对表单中的数据编码。比如我们在jsp页面第一行所写的:<%@page contentType="text/html;charset=UTF-8"%>。那么这个网页响应给客户端后使用的就是utf-8编码,那么post时使用的也是这个编码。
编码后的格式可以参考java中的URLEncoder.encode方法编码的结果。
4. 服务器底层如何处理提交的数据。
上面2已经提到,客户端和服务器端传输的是字节,那么服务器端接收到的原始数据就是字节。但是我们的程序通常需要从服务器获取字符,而不是字节,所以服务器端必须将字节转换为字符。这里也涉及编码,服务器采取什么编码方式将字节转换为字符?我想也是iso-8859-1,这样和客户端的编码方式一致,不会产生乱码,相当于一个还原字符的过程。这里有个问题,比如客户端发送:name=%D6%D0%B9%FA,那么服务器端还原后也是:name=%D6%D0%B9%FA。那么我们使用request.getParameter(“name”)如何能得到正确的值呢?难道要我们自己再进行转换?答案是:NO。根据Servlet规范,Servlet中获取数据的方法会按照指定的字符集解码。指定的字符集是什么?默认是iso-8859-1。正是因为使用了iso-8859-1解码我们发送的参数,导致了乱码的产生,这里才是产生乱码的源头。具体解码的过程可以看看java的URLDecode.decode方法。既然知道了产生乱码的原因是因为服务器默认使用iso-8859-1解码,那我们就得想办法更改服务器使用的解码编码。好在服务器已经提供给我们修改的方式了,我们可以在服务器中进行配置,比如Tomcat可以在server.xml中进行配置,比如:URIEncoding="GBK"这样服务器就会使用gbk编码解码,这种方式主要针对GET提交的数据,对于POST更常用的是request.setCharacterEncoding(String charset)设置解码编码。
5. 为了避免乱码,客户端应该如何做?
GET:
对于含有非ASCII字符的URL自己进行编码,比如使用javascript中的方法进行编码。这样就不需要浏览器为我们编码了,从而解决了浏览器编码的不确定性。
POST:
只要正确设置网页编码即可。