摘自:http://blog.csdn.net/yzhz/archive/2007/07/03/1676796.aspx
1 问题:
编码问题是JAVA初学者在web开发过程中经常会遇到问题,网上也有大量相关的文章介绍,但其中很多文章并没有对URL中使用了中文等非ASCII的字符造成服务器后台程序解析出现乱码的问题作出准确的解释和说明。本文将详细介绍由于在URL中使用了中文等非ASCII的字符造成乱码的问题。
1.1 在URL中中文字符通常出现在以下两个地方:
1.2 出现乱码问题的原因主要是以下几方面:
2 基础知识:
2.1 一个http请求经过的几个环节:
浏览器(ie/firefox)【get/post】------------>Servlet服务器------------------------------->浏览器显示
编码------------------------------------------->解码成unicode,然后将显示的内容编码---->解码
当对字符串进行编码和解码的时候都涉及到字符集,通常使用的字符集为ISO8859-1、GBK、UTF-8、UNICODE。
2.2 URL的组成:
域名:端口/contextPath/servletPath/pathInfo?queryString
对于weblogic: contextPath是在应用的weblogic.xml中配置。 <context-root>/</context-root> 对于tomcat: contextPath是在server.xml中配置。 <Context path="/" docBase="D:/server/blog.war" debug="5" reloadable="true" crossContext="true"/> 对于jboos: contextPath是在应用的jboss-web.xml中配置。 <jboss-web> <context-root>/</context-root> </jboss-web>
<servlet-mapping> <servlet-name>Example</servlet-name> <url-pattern>/example/*</url-pattern> </servlet-mapping>
2.3 Servlet API
我们使用以下servlet API获取URL的值及参数。
2.4 开发人员必须清楚的servlet规范:
- 告诉浏览器网页中数据是什么编码;
- 表单提交时,通常浏览器会根据ContentType指定的charset对表单中的数据编码,然后发送给服务器的。
- 这里需要注意的是:这里所说的ContentType是指http头的ContentType,而不是在网页中meta中的ContentType。
3 下面我们从浏览器和应用服务器来举例说明:
URL:http://localhost:8080/example/中国?name=中国
汉字 编码 二进制表示 中国 UTF-8 0xe4 0xb8 0xad 0xe5 0x9b 0xbd[-28, -72, -83, -27, -101, -67] 中国 GBK 0xd6 0xd0 0xb9 0xfa[-42, -48, -71, -6] 中国 ISO8859-1 0x3f,0x3f[63, 63]信息失去
3.1 浏览器
3.1.1 GET方式提交,浏览器会对URL进行URL encode,然后发送给服务器。
http://localhost:8080/example/中国?name=中国 实际上提交是: GET /example/%E4%B8%AD%E5%9B%BD?name=%D6%D0%B9%FA
http://localhost:8080/example/中国?name=中国 实际上提交是: GET /example/%D6%D0%B9%FA?name=%D6%D0%B9%FA
http://localhost:8080/example/中国?name=中国 实际上提交是: GET /example/%D6%D0%B9%FA?name=%D6%D0%B9%FA
很显然,不同的浏览器以及同一浏览器的不同设置,会影响最终URL中PathInfo的编码。对于中文的IE和FIREFOX都是采用GBK编码QueryString。
GET方式提交 小结:
比如: URL:http://localhost:8080/example/中国?name=中国 建议: URL:http://localhost:8080/example/%D6%D0%B9%FA?name=%D6%D0%B9%FA
3.1.2 POST提交
对于POST方式,表单中的参数值对是通过request body发送给服务器,此时浏览器会根据网页的ContentType("text/html; charset=GBK")中指定的编码进行对表单中的数据进行编码,然后发给服务器。
在服务器端的程序中我们可以通过Request.setCharacterEncoding() 设置编码,然后通过request.getParameter获得正确的数据。
解决方案:从最简单,所需代价最小来看,我们对URL以及网页中的编码使用统一的编码对我们来说是比较合适的。
如果不使用统一编码的话,我们就需要在程序中做一些编码转换的事情。这也是我们为什么看到有网络上大量的资料介绍如何对乱码进行处理,其中很多解决方案都只是一时的权宜之计,没有从根本上解决问题。
3.2 Servlet服务器
Servlet服务器实现的Servlet遇到URL和POST提交的数据中含有%的字符串,它会按照指定的字符集解码。下面两个Servlet方法返回的结果都是经过解码的:
这里所说的"指定的字符集"是在应用服务器的配置文件中配置。
对于tomcat服务器,该文件是server.xml <Connector port="8080" protocol="HTTP/1.1" maxThreads="150" connectionTimeout="20000" redirectPort="8443" URIEncoding="GBK"/> URIEncoding告诉服务器servlet解码URL时采用的编码。 <Connector port="8080" ... useBodyEncodingForURI="true" /> useBodyEncodingForURI告诉服务器解码URL时候需要采用request body指定的编码。
对于weblogic服务器,该文件是weblogic.xml <input-charset> <java-charset-name>GBK</java-charset-name> </input-charset>
3.3 浏览器显示
浏览器根据http头中的ContentType("text/html; charset=GBK"),指定的字符集来解码服务器发送过来的字节流。我们可以调用HttpServletResponse.setContentType()设置http头的ContentType。
4 总结:
所以我们建议URL中不要使用中文等非ASCII字符,如果含有非ASCII字符的话要使用URLEncode编码一下,比如: http://localhost:8080/example1/example/中国 正确的写法: http://localhost:8080/example1/example/%E4%B8%AD%E5%9B%BD 并且我们建议URL中不要在PathInfo和QueryString同时使用非ASCII字符,比如 http://localhost:8080/example1/example/中国?name=中国 原因很简单:不同浏览器对URL中PathInfo和QueryString编码时采用的字符集不同,但应用服务器对URL通常会采用相同的字符集来解码。