一、问题: 编码问题是JAVA初学者在web开发过程中经常会遇到问题,网上也有大量相关的文章介绍,但其中很多文章并没有对URL中使用了中文等非ASCII的字符造成服务器后台程序解析出现乱码的问题作出准确的解释和说明。本文将详细介绍由于在URL中使用了中文等非ASCII的字符造成乱码的问题。
1、在URL中中文字符通常出现在以下两个地方: (1)、Query String中的参数值,比如http://search.china.alibaba.com/search/offer_search.htm?keywords=中国 (2)、servlet path,比如:http://search.china.alibaba.com/selloffer/中国.html
2、出现乱码问题的原因主要是以下几方面: (1)、浏览器:我们的客户端(浏览器)本身并没有遵循URI编码的规范(http://www.w3.org/International/O-URL-code.html)。 (2)、Servlet服务器:Servlet服务器的没有正确配置。 (3)、开发人员并不了解Servlet的规范和API的含义。
二、基础知识: 1、一个http请求经过的几个环节:浏览器(ie firefox)【get/post】------------>Servlet服务器---------------------------- --->浏览器显示 编码 解码成unicode,然后将显示的内容编码 解码 (1) 浏览器把URL(以及post提交的内容)经过编码后发送给服务器。 (2) 这里的Servlet服务器实际上指的是由Servlet服务器提供的servlet实现ServletRequestWrapper,不同应用服务器的 servlet实现不同,这些servlet的实现把这些内容解码转换为unicode,处理完毕后,然后再把结果(即网页)编码返回给浏览器。 (3) 浏览器按照指定的编码显示该网页。
当对字符串进行编码和解码的时候都涉及到字符集,通常使用的字符集为ISO8859-1、GBK、UTF-8、UNICODE。
2、URL的组成: 域名:端口/contextPath/servletPath/pathInfo?queryString 说明:
1、ContextPath是在Servlet服务器的配置文件中指定的。对于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>
2、ServletPath是在应用的web.xml中配置。 <servlet-mapping> <servlet-name>Example</servlet-name> <url-pattern>/example/*</url-pattern> </servlet-mapping>
2、Servlet API 我们使用以下servlet API获得URL的值及参数。 request.getParameter("name"); // 获得queryString的参数值(来自于get和post),其值经过Servlet服务器URL Decode过的 request.getPathInfo(); // 注意:pathinfo返回的字符串是经过Servlet服务器URL Decode过的。 requestURI = request.getRequestURI(); // 内容为:contextPath/servletPath/pathinfo 浏览器提交过来的原始数据,未被Servlet服务器URL Decode过。
3、开发人员必须清楚的servlet规范: (1) HttpServletRequest.setCharacterEncoding()方法 仅仅只适用于设置post提交的request body的编码而不是设置get方法提交的queryString的编码。该方法告诉应用服务器应该采用什么编码解析post传过来的内容。很多文章并没有说明这一点。 (2) HttpServletRequest.getPathInfo()返回的结果是由Servlet服务器解码(decode)过的。 (3) HttpServletRequest.getRequestURI()返回的字符串没有被Servlet服务器decoded过。 (4) POST提交的数据是作为request body的一部分。 (5) 网页的Http头中ContentType("text/html; charset=GBK")的作用: (a) 告诉浏览器网页中数据是什么编码; (b) 表单提交时,通常浏览器会根据ContentType指定的charset对表单中的数据编码,然后发送给服务器的。 这里需要注意的是:这里所说的ContentType是指http头的ContentType,而不是在网页中meta中的ContentType。
三、下面我们分别从浏览器和应用服务器来举例说明: 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]信息失去
(一)、浏览器 1、GET方式提交,浏览器会对URL进行URL encode,然后发送给服务器。 (1) 对于中文IE,如果在高级选项中选中总以UTF-8发送(默认方式),则PathInfo是URL Encode是按照UTF-8编码,QueryString是按照GBK编码。 http://localhost:8080/example/中国?name=中国实际上提交是: GET /example/%E4%B8%AD%E5%9B%BD?name=%D6%D0%B9%FA
(1) 对于中文IE,如果在高级选项中取消总以UTF-8发送,则PathInfo和QueryString是URL encode按照GBK编码。实际上提交是: GET /example/%D6%D0%B9%FA?name=%D6%D0%B9%FA
(3) 对于中文firefox,则pathInfo和queryString都是URL encode按照GBK编码。实际上提交是: GET /example/%D6%D0%B9%FA?name=%D6%D0%B9%FA
很显然,不同的浏览器以及同一浏览器的不同设置,会影响最终URL中PathInfo的编码。对于中文的IE和FIREFOX都是采用GBK编码QueryString。
小结:解决方案: 1、URL中如果含有中文等非ASCII字符,则浏览器会对它们进行URLEncode。为了避免浏览器采用了我们不希望的编码,所以最好不要在URL中直接使用非ASCII字符,而采用URL Encode编码过的字符串%. 比如: URL:http://localhost:8080/example/中国?name=中国建议: URL:http://localhost:8080/example/%D6%D0%B9%FA?name=%D6%D0%B9%FA
2、我们建议URL中PathInfo和QueryString采用相同的编码,这样对服务器端处理的时候会更加简单。
2、还有一个问题,我发现很多程序员并不明白URL Encode是需要指定字符集的。不明白的人可以看看这篇文档:http://gceclub.sun.com.cn/Java_Docs/html/zh_CN/api/java/net/URLEncoder.html
2、 POST提交 对于POST方式,表单中的参数值对是通过request body发送给服务器,此时浏览器会根据网页的ContentType("text/html; charset=GBK")中指定的编码进行对表单中的数据进行编码,然后发给服务器。在服务器端的程序中我们可以通过Request.setCharacterEncoding() 设置编码,然后通过request.getParameter获得正确的数据。
解决方案: 1、从最简单,所需代价最小来看,我们对URL以及网页中的编码使用统一的编码对我们来说是比较合适的。如果不使用统一编码的话,我们就需要在程序中做一些编码转换的事情。这也是我们为什么看到有网络上大量的资料介绍如何对乱码进行处理,其中很多解决方案都只是一时的权宜之计,没有从根本上解决问题。
(二)、Servlet服务器 Servlet服务器实现的Servlet遇到URL和POST提交的数据中含有%的字符串,它会按照指定的字符集解码。下面两个Servlet方法返回的结果都是经过解码的: request.getParameter("name"); request.getPathInfo();
这里所说的"指定的字符集"是在应用服务器的配置文件中配置。
(1) tomcat服务器对于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指定的编码。
(2) weblogic服务器对于weblogic服务器,该文件是weblogic.xml <input-charset> <java-charset-name>GBK</java-charset-name> </input-charset>
(三)浏览器显示 浏览器根据http头中的ContentType("text/html; charset=GBK"),指定的字符集来解码服务器发送过来的字节流。我们可以调用 HttpServletResponse.setContentType()设置http头的ContentType。
总结: 1、URL中的PathInfo和QueryString字符串的编码和解码是由浏览器和应用服务器的配置决定的,我们的程序不能设置,不要期望用request.setCharacterEncoding()方法能设置URL中参数值解码时的字符集。所以我们建议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通常会采用相同的字符集来解码。
2、我们建议URL中的URL Encode编码的字符集和网页的contentType的字符集采用相同的字符集,这样程序的实现就很简单,不用做复杂的编码转换。
分享到:
相关推荐
url-loader可以将小尺寸图片转换成Data URL格式的Base64编码字符串内嵌到代码中,而file-loader则是负责把大尺寸图片拷贝到输出目录,并返回图片的公共URL路径。这两个Loader通常联合使用,优化了资源的加载方式,...
根据提供的文件信息,我们可以整理出一系列关于Java的重要知识点,这些知识点涵盖了Java基础知识、容器管理、多线程处理、反射机制、对象拷贝以及Java Web开发等几个方面。 ### Java基础知识 1. **JDK和JRE的区别*...
9:采用Messenger的弹出滑动消息提示框. 10:下载管理,虚拟文件夹. 11:自动ping. 12:连接到搜索引擎. 13:自动报告bug,建议等. 14:宏功能. 15:自动同步文件夹. 16:保存加载任务. 17:计划任务. 18:单线程下载时不能创建...
- **copy模块**:提供了浅拷贝和深拷贝的功能。 - **sys模块**:提供了访问解释器环境变量的方法。 - **atexit模块**:支持在程序退出时执行清理工作。 - **time模块**:提供了处理时间和日期的方法。 - **...
- **实践建议**:谨慎使用`ICloneable`,因为它的实现可能导致深拷贝或浅拷贝的问题。 ### 24. 使用转换运算符 - **重要性**:转换运算符使得类型之间可以相互转换。 - **实践建议**:为类定义适当的转换运算符,...
《Netty in Action》中文版是一本专注于Java网络编程框架...总之,《Netty in Action》中文版是一本深入浅出的Netty指南,无论你是初学者还是有经验的开发者,都能从中受益匪浅,提升自己在网络编程领域的专业能力。
12. **编码解码**:在网络通信中,编码和解码是常见的操作,funx-js可能包含Base64、URL编码等工具。 通过这些工具函数,funx-js可以极大地提高开发效率,减少代码量,并且保持代码的一致性和可维护性。在实际使用...
vc++动态链接库(dll)编程深入浅出 内含开发文档。主要是对动态链接库的教程。 vc++动态链接库编程之DLL典型实例源代码下载 VC++仿Dreamweaver取色器源代码 VC++挂机锁屏系统源程序 VC++建立桌面或开始菜单快捷方式 ...
"Python天天美味"系列是一组深入浅出的Python编程教程,涵盖了从基础语法到高级特性的广泛主题。以下是对各个部分的关键知识点的详细说明: 1. **交换变量**:Python中可以直接通过`a, b = b, a`来实现两个变量的值...
当需要将文本字符串转换成适合URL的形式时,使用`URLEncoder`进行编码。 11. **线程状态与状态迁移**: 线程有新建、可运行、运行、阻塞和死亡五种状态。线程启动后,通过`start()`方法进入可运行状态,然后根据...
vc++动态链接库(dll)编程深入浅出 内含开发文档。主要是对动态链接库的教程。 vc++动态链接库编程之DLL典型实例源代码下载 VC++仿Dreamweaver取色器源代码 VC++挂机锁屏系统源程序 VC++建立桌面或开始菜单快捷方式 ...
vc++动态链接库(dll)编程深入浅出 内含开发文档。主要是对动态链接库的教程。 vc++动态链接库编程之DLL典型实例源代码下载 VC++仿Dreamweaver取色器源代码 VC++挂机锁屏系统源程序 VC++建立桌面或开始菜单快捷方式 ...
vc++动态链接库(dll)编程深入浅出 内含开发文档。主要是对动态链接库的教程。 vc++动态链接库编程之DLL典型实例源代码下载 VC++仿Dreamweaver取色器源代码 VC++挂机锁屏系统源程序 VC++建立桌面或开始菜单快捷方式 ...
vc++动态链接库(dll)编程深入浅出 内含开发文档。主要是对动态链接库的教程。 vc++动态链接库编程之DLL典型实例源代码下载 VC++仿Dreamweaver取色器源代码 VC++挂机锁屏系统源程序 VC++建立桌面或开始菜单快捷方式 ...