(转)解析WEB开发编码问题
?
?
从上面的表格可以 看出,Websphere6.1,apusic5.1应用服务器的get和post方法其getParameter解码所用的字符集是 setCharacterEncoding所指定的字符集,tomcat5的post方法使用的是setCharacterEncoding,但是get 方法却不是。再回过头看看这几个试验的过程,浏览器使用post方法时将会采用页面的字符集进行编码成字节流发送到服务器,服务器接收到字节流后根据 setCharacterEncoding设定的字符集进行解码,获得字符串,也就是说,如果使用post方法提交,只要保证“页面的编码的字符 集=setCharacterEncoding设置的字符集”那么getParameter获得的值就是正确的,get和超链接的方式类似,表单使用 get提交时,会根据页面的编码进行encodeURI,超链接的方式程序可以根据指定的字符集进行URI编码,两种方式的共同点是浏览器都会进行URI 编码,在Websphere中,get和超链接的方式只要“URI编码的字符集=setCharacterEncoding的字符集”,那么 getParameter的结果就是正确的,而使用get提交表单时其“URI编码的字符集=页面编码的字符集”,超链接的URI编码的字符集在上面说 过,chrome和Firefox浏览器中URI编码的字符集=页面编码的字符集,但是IE却不是,没有规律。
tomcat5.5 中getParameter获取get方法或超链接传过来的参数时默认会用ISO8859-1进行解码,例如浏览器发送UTF-8的编码的请 求,tomcat5.5的getParameter使用ISO8859-1解码,这时的结果是错的,如果要获得正确的值,需要在tomcat5.5的 getParameter的时候采用UTF-8进行解码,通过设置URIEncoding="UTF-8"或者 useBodyEncodingForURI="true",就能让tomcat在的getParameter时采用UTF-8解码 (useBodyEncodingForURI="true"表示解码的字符集采用与页面编码相同的字符集),如果不通过配置要并且需要获得正确的值,则 需要程序进行转码,因为getParameter是通过ISO8859-1解码的,所有先通过 getParameter().getBytes("ISO8859-1")编码成原来的字节数组,然后使用UTF-8字符集解码为字符串:new String(getParameter().getBytes("ISO8859-1"),"UTF-8")
3.设置浏览器的页面编码
服务器向浏览器发送的也是经过编码成字节流在网络上传输,浏览器接收到字节流之后使用指定的 字符集解码成字符串再进行展现,如果这两个环节的字符集不一致也会导致乱码的问题,例如静态HTML文件或jsp中都是以UTF-8保存的,则需要告诉浏 览器用UTF-8来进行解码,如果是jsp可以通过<%@ page contentType="text/html; charset=UTF-8" language="java" %>来进行设置,静态文件可以通过 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> 进行设置,如果在servlet中直接进行输出,可以通过response.setCharacterEncoding("UTF- 8"),setContentType("text/html;charset=UTF-8"),setHeader("Content- Type","text/html;charset=UTF-8")进行设置,这些操作都相当于在response的头部增加"Content- Type:text/html;charset=UTF-8"信息,header中的编码信息的优先级要高于html的meta标签,也就是说如果 serlvet中设置了setContentType("text/html;charset=UTF-8"),jsp设置了<meta http-equiv="Content-Type" content="text/html; charset=GBK"/>则浏览器会按照UTF-8字符集进行解码,需要说明的是,servlet这些设置浏览器编码格式的方法需要在进行输入 之前调用,jsp的page指令也需要在输出内容的行之前。正如前面实验所看到的,浏览器的页面编码不仅决定了浏览器按照什么字符集解码从服务器传输过来 的字节流,还决定了浏览器按照什么字符集进行编码向服务器发送请求。
4.设置HTML文件和jsp文件的编码,设置jsp编译的编码
文件存储的编码格式要和页面的编码集一致,否则将导致写在页面上的汉字出现乱码问题,例如 HTML文件中设置页面的编码为UTF-8格式,那么此文件的存储格式也应该为UTF-8的,可以通过记事本或者Editplus打开文件,选择另存为, 然后编码选择UTF-8,覆盖原来的文件即可。jsp文件和html文件一样,页面的编码和文件保存的编码要一致,而且要指定jsp的编译编码和文件的保 存编码一致,也就是pageEncding的值要和文件保存的编码一致。
如何解决乱码问题
1).统一编码:页面编码=URI编码=setCharacterEncoding=文件保 存编码=jsp编译编码,这种解决方法能解决绝大部分的乱码问题,在WebSphere服务器,apusic服务器,post和get都能获得正确的值, 但是在tomcat5.5中get方式还是会出现乱码,可以设置URIEncoding="UTF-8"或者 useBodyEncodingForURI="true"来解决,这种方法付出的代价最小,效率也最高,应该使用这种方法来解决乱码问题。
2).两次次URI编码,服务器URI解码:在程序中由程序进行2次URI编码,其原理是利 用不同服务器其默认解码字符集对ASC字符的解码结果是一样的,例 如:url="TestServlet?test="+encodeURI(encodeURI("中")),浏览器发送的结果 为:TestServlet?test=%25E4%25B8%25AD,应用服务器遇到%号开头的字节会进行解码,不同的应用服务器,都会将%25解析 为%,所以参数被析为test=%E4%B8%AD,也即是说getParameter("test")的值为%E4%B8%AD,这就是“中”的 UTF-8的URI编码,通过java.net.URLDecoder.decode(getParameter("test"),"UTF-8")便可 获得字符“中”,这种方法不需要设置服务器的setCharacterEncoding,也不用关系页面的编码字符集,但是需要手动进行URI编码,后台 还需要进行一次URL解码,适合解决少数乱码问题。
3).BASE64编码:参数先经过BASE64编码,服务器端在进行BASE64解 码,BASE64是可逆的编码方式,编码后都是ASC字符,能在浏览器和应用服务器之间安全的传输而不会出现乱码。不过和方法2一样,需要进行一次 BASE64编码和解码,并且还需要在页面和后台添加支持BASE64编码和解码的函数,这种方式也只适合于解决少数乱码问题,和方法2相 比,BASE64更适合于解决参数中有特殊符号的情况。
4).转码:将错误的字符串编码还原为原来的字节数组,然后用此字节数组通过正确的字符集解 码为正确的字符串,例如:new String(request.getParamter("test").getBytes("ISO8859-1"),"UTF-8"),使用这种方法 的前提是需要知道浏览器发送过来的编码字符集,和服务器解码所使用的字符集,上面例子中表示应用服务器解码的字符集是ISO8859-1,浏览器发送过来 编码所用字符集是UTF-8,这种方法需要根据应用服务器的编码来进行转换,不同的应用服务器可能不同,所用此方法并不通用,只适合于解决在某个具体应用 服务器中出现的乱码问题。
?
总结
字符->字节:编码,字节->字符:解码URI编码是用一个字符串表示另一个字符串,URI编码就是用要编码的字符串根据指定的字符集解码后每个字节码前加上%组织的字符串,例如“中”的UTF-8编码为E4 B8 AD三个字节,那么其UTF-8的URI编码为:%E4%B8%AD组织的字符串浏览器的发送给服务器的URL只能包含ASC字符,如果URL中包含非ASC字符,浏览器会进行URI编码post提交时,表单的数据会根据页面编码的字符集进行编码发送到浏览器(每个form也可以单独设置编码字符集,如果没设置则采用页面的编码字符集)get提交时,表单中的数据会根据页面的字符集进行URI编码链接中直接带有非ASC字符时,浏览器也会进行编码,但编码所用的字符集跟浏览器有关需要在url后面添加非ASC字符的参数时,更安全的做法是自己进行根据指定的字符集进行URI编码,因为不同的浏览器编码结果可能不一样request.getParameter获得值经过了服务器的解码,POST方法时所有的服务器都是通过 setCharacterEncoding进行解码的,GET方法时,WebSphere和apusic也是使用 setCharacterEncoding指定的字符集进行解码,tomcat5则是通过ISO8859-1进行解码可以通过调整tomcat5的配置来指定get方法时request.getParameter解码所用的字符集,修改server.xml中 Connecter元素,增加属性URIEncoding="UTF-8"设定字符集,或者增加属性 useBodyEncodingForURI="true"表示使用页面的编码所用的字符集解决乱码的最好方法是编码5统一:页面编码=URI编码=setCharacterEncoding=文件保存编码=jsp编译编码