乱码问题小结

个人专题目录

一、问题:

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服务器的配置文件中指定的。

对于tomcat:

contextPath是在server.xml中配置。

<Context path="/" docBase="D:/server/blog.war" debug="5" reloadable="true" crossContext="true"/>

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

(2) 对于中文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

1.在页面中对你的URL进行编码

  使用------encodeURI(你要使用的中文参数值)如:...?username"+encodeURI(“小甜甜")

2.在后台通过解码来接收该中文参数

 使用----String name = new String(request.getParameter("username ").getBytes("iso8859-1"),"utf-8")

3.最好不要在URL中传递中文参数

假设

keyWord ='阳光';

url="play.jsp? keyWord ="+ keyWord

若按照上述的地址直接访问,则中文会变成乱码。必须使用encodeURI()进行两次编码。如下:

url="play.jsp? keyWord ="+encodeURI(encodeURI( keyWord ));

服务器通过以下方式获取值:

keyWord =URLDecoder.decode( keyWord ,"utf-8");

则中文乱码问题解决。

2、我们建议URL中PathInfo和QueryString采用相同的编码,这样对服务器端处理的时候会更加简单。

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指定的编码。

(二)浏览器显示

    浏览器根据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的字符集采用相同的字符集,这样程序的实现就很简单,不用做复杂的编码转换。

function verify() {

//解决中文乱麻问题的方法1,页面端发出的数据作一次encodeURI,

服务器段使用进行转移成UTF-8;

//解决中文乱麻问题的方法2,页面端发出的数据作两次encodeURI,

这个做的好处在于,不管浏览器用户在页面来设置编码,服务器所采用的编码来做一次URLencode转换成UTF-8.

var url = "AJAXServer?name=" + encodeURI(encodeURI($("#userName").val()));

url = convertURL(url);

$.get(url,null,function(data){

$("#result").html(data);

});

}

说明:1 .encodeURL函数主要是来对URI来做转码,它默认是采用的UTF-8的编码.

\2. UTF-8编码的格式:一个汉字来三个字节构成,每一个字节会转换成16进制的编码,同时添加上%号.

其中具体的原理分析如下,假设页面端输入的中文是一个“中”,按照下面步骤进行解码

1.第一次encodeURI,按照utf-8方式获取字节数组变成[-28,-72-83],对字节码数组进行遍历,把每个字节转化成对应的16进制数,这样就变成了[E4,B8,AD],最后变成[%E4,%B8,%AD]

2.第二次encodeURI,把数组最后变成[%25E4,%25B8,%25AD]然后就把处理后的数据[%25E4,%25B8,%25AD]发往服务器端,

当应用服务器调用getParameter方法,getParameter方法会去向应用服务器请求参数

应用服务器最初获得的就是发送来的[%25E4,%25B8,%25AD],应用服务器会对这个数据进行URLdecode操作,URldecode操作和encodeURL操作是相反的操作,处理结果就是[%E4,%B8,%AD],并把这个值返回给getParameter方法

然后再在服务器端中调用相应的URL转码方法或者是函数 就可以把数据还原成最初页面发送过来的中文“中”了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,186评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,858评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,620评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,888评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,009评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,149评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,204评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,956评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,385评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,698评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,863评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,544评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,185评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,899评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,141评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,684评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,750评论 2 351

推荐阅读更多精彩内容