• 2009-09-08

    ajax提交的乱码问题 - [javascript]

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://www.my1px.cn/logs/45994312.html

    一向写html都是用的utf-8,现在却要用GB的,在做ajax请求的时候,java程序员说我提交过去的都是乱码....晕....

    后来问清羽师父(顺便夸一下我师父,是个性格内敛,办事有条理,个性很好的人^_^,在TB,平日里,七七八八的问题都多亏了他了。我觉得他很厉害,只是不爱表现...),通过ajax请求地址后面加?_input_charset=utf-8解决了问题,原来开发那个有个框架会根据这个参数自动处理。和和,差点急死,开发那边居然要求我把传过去的数据转变编码,我晕死!

    问题是解决了,可问题怎么来的呢?

    百度了一下编码的知识:(以下引用自51goodhome的空间

    1、编码
          编码比较常用的有: UTF-8, GBK, GB2312, ISO-8859-1,除了 iso-8859-1之外的其它三个编码都能很好的支持中文,但它们都兼容 ISO-8859-1的编码(就是说无论编码怎么改变,只要是 ISO-8859-1中的字符,永远不会出现乱码)。
          这四种编码中, GB2312是中国规定的汉字编码,也可以说是简体中文的字符集编码;GBK 是 GB2312的扩展 ,除了兼容GB2312外,它还能显示繁体中文,还有日文的假名;而 UTF-8虽然也支持中文,但却与GB码不兼容(编码值不同)。UTF-8使用的是可变长的 UNICODE编码,编码可能是 1位 16进制(即 ISO-8859-1中的字符,其编码也是相同的)也有可能是 2位或 3位的 16进制。 UTF-8的优点是:1、与CPU字节顺序无关 , 可以在不同平台之间交流。 2、容错能力高 , 任何一个字节损坏后 , 最多只会导致一个编码码位损失 , 不会链锁错误 (如 GB码错一个字节就会整行乱码 ),所以在国际化处理中基本都是建议使用 UTF-8作为编码。

    2、文件的编码
          文件编码最常使用的有两种:ANSI和UTF-8,光看名字估计你都可以猜到了,ANSI就是我们保存文件时使用的默认编码,而UTF-8则需自己设置。对于编码的改变,我使用的工具是NOTEPAD和ECLIPSE,NOTEPAD使用最简单,只要打开文件后在另存为中选择相应的编码就行了,而且它对编码的支持非常好;而在ECLIPSE中,只要稍微设置一下就行了,打开首选项,然后选择:常规->内容类型(ContentType),在右边选中你想改变保存编码的文件类型,然后在下方的缺省编码中改变其值,最后点击更新(UPDATE)按钮即可。


    而在其它的编辑器中,默认保存的内容都是GB2312或者GBK(NOTEPAD中对应ANSI).而根据前面所说的UTF-8和GBK,GB2312等 的编码值是不同的这一点,可以知道,如果文件使用了UTF-8,那么字符编码就必须使用UTF-8,否则编码值的不同就可能造成乱码。而这也就是为什么那 么多的人使用了UTF-8编码后还会产生乱码的根本原因。(JS和JSP都是这个道理)

    另外,还附了一个解决ajax里乱码的方法:

    6、AJAX提交数据乱码,返回数据乱码的解决方案

         万变不离其宗,AJAX的乱码问题自然跟编码有关了,其实很多人跟我一样想到了对文件编码进行设置,并且在接数据时设置了requet的编码,在返回的数 据时设置了response的编码一切都以为会很顺利,可是这一切都是徒劳无功的,讨厌的乱码再一次出现在你眼前。在你试了N多种方法,包括JS自身的 escape,unescape方法后,你发现乱码仍然猖狂地出现在屏幕上。
        其实在试过这N多方法后,很多人都没发现,解决的方法其实很简单,而且其答案就在我们之前处理的JSP乱码之中。让我们先看一下AJAX的经典请求代码

    xmlhttp.open( "post", url, async );
    xmlhttp.setRequestHeader( "Content-Type", "text/html" );
    xmlhttp.send( params );

    通过前面的说明,不知道你现在看出端倪了没有。不知道是受了网上教程的影响还是其它方面影响,setRequestHeader并是万年不变的,也没人想过去改它,而问题就正好出在这个地方。回想一个JSP页面内容的编码设置,其中有这么一节:

    contentType="text/html; charset=UTF-8"

    现在知道问题了吧,所以我们要把第二句代码改为:

    xmlhttp.setRequestHeader( "Content-Type", "text/html;charset=UTF-8" );

    如果提交的是form,那么设置为"application/x-www-form-urlencoded; charset=UTF-8"

    最后别忘了在返回数据时也设置上:

    response.setContentType( "text/xml" );
    response.setCharacterEncoding( "UTF-8" );

    如果要问为什么的话,其实我们可以把xmlhttp看成是一个临时页面,它由浏览 器动态生成,主要作用是在后台获得请求的数据(可以看成是一个高级的iframe)。所以对于普通页面设置的编码,对它也要同样设置。而在servlet 中返回数据为什么要设置contentType和encoding其道理也是一样的。众所周知,jsp的最后形态就是servlet,而jsp页首设置的 那个内容其实也就是让生成的servlet中生成这么两句话:

    response.setContentType( "text/html" );
    response.setCharacterEncoding( "UTF-8" );

    而pageEncoding则是跟jvm说明了这个页面的内容要使用什么编码保存(这跟之后生成的CLASS有关系)。所以在servlet设置response的编码也是理所当然的了。

    response.setContentType("text/xml;charset=UTF-8");

    response.setHeader("Pragma",   "no-cache");   //HTTP   1.0  

    response.setDateHeader("Expires",   0);   //prevents   caching   at   the   proxy   server  

    PrintWriter out = response.getWriter();

    out.write(outXML);

    out.flush();

    out.close();

    OK!这样向客户端写的数据中的中文也是UTF-8编码了,客户端js脚本获取到request.responseXML也好,responseText也好,里面的数据都不会有乱码了

    =====================================================================================

    OK,yui是不是也是这么处理的呢?我翻了一下connection-debug,发现在用post方法时,用initHeader定义了Content-Type,但值是'application/x-www-form-urlencoded; charset=UTF-8',如果是传文件(uploadFile)就是'multipart/form-data',而不是'text/xml;charset=UTF-8'.application/x-www-form-urlencoded我一般看都是写在form表单上的,到底干什么用的,汗死。goooooooooooooogle:表单元素的enctype属性指定的是表单数据的编码方式,该属性有3个值:

      1) application/x-www-form-urlencoded:这是默认编码方式,它只处理表单域里的value属性值,采用这种编码方式的表单会将表单域的值处理成URL编码方式。

      2) multipart/form-data:这种编码方式的表单会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定文件的内容也封装到

    请求参数里。

      3) text/plain:这种方式主要适用于直接通过表单发送邮件的方式。

      文件上传是web应用经常用到的一个知识。原理是,通过为表单元素设置enctype=”multipart/form-data”属性,让表单提交的数据以二

    进制编码的方式提交,在接收此请求的Servlet中用二进制流来获取内容,就可以取得上传文件的内容,从而实现文件的上传。


    当action为get时候,浏览器用x-www-form-urlencoded的编码方式把form数据转换成一个字串(name1=value1& amp;name2=value2...),然后把这个字串append到url后面,用?分割,加载这个新的url。
    当action为post时候,浏览器把form数据封装到http body中,然后发送到server。
    如果没有type=file的控件,用默认的application/x-www-form-urlencoded就可以了。
    但 是如果有type=file的话,就要用到multipart/form-data了。浏览器会把整个表单以控件为单位分割,并为每个部分加上 Content-Disposition(form-data或者file),Content-Type(默认为text/plain),name(控件 name)等信息,并加上分割符(boundary)。如果有以下form,并选择了file1.txt上传
    <form action="http://server.com/cgi/handle"
           enctype="multipart/form-data"
           method="post">
       <input type="text" name="submit-name" value="chmod777"><br />
       What files are you sending? <input type="file" name="files"><br />
    </form>

    则有如下body:
    Content-Type: multipart/form-data; boundary=AaB03x

       --AaB03x
       Content-Disposition: form-data; name="submit-name"

       chmod777
       --AaB03x
       Content-Disposition: form-data; name="files"; filename="file1.txt"
       Content-Type: text/plain

       ... contents of file1.txt ...
       --AaB03x--


    看来就是指ajax提交过去post数据的方式?


    历史上的今天:


    收藏到:Del.icio.us