雪峰

和你一起 实现梦想

Ajax中文乱码解决方案

分类: 综合开发 1970-01-01 08:00:00 阅读(68)

主流浏览器中 Ajax 对象请求时都以 UTF-8 编码发送数据,所以当前后端文件都统一用 UTF-8 编码时情况比较经典而单纯。如果确实需要 GB 字符集,则需要适当变通。这里就这两种字符集分别说明解决方案。服务器端文件以 PHP 举例。

下列方案在 IE 系、FireFox3、Chrome4、Opera10 测试通过。

UTF-8 经典方案

前后端文件本身统一都用 UTF-8 编码。

HTML 文件使用声明:

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  

JavaScript 文件也要存为 UTF-8 模式,最终确保传递参数始终以 UTF-8 编码的核心是把参数值统一用 encodeURIComponent() 处理。即 SF.HTTP.xhr_utf.js 中的如下这行

param = encodeURIComponent(param);  

注意此时后台 PHP 程序接收到的请求数据是 UTF-8 编码的,如果需要转成其它字符集的数据可以用 iconv 进一步处理。PHP 程序输出数据也必须是 UTF-8 编码的,加声明:

header("text/html;charset=UTF-8");   

注意要让 IE 正常接收 UTF8 的数据,必须写大写的"UTF-8",而不能用小写或其它写法!

以下是各文件完整的代码:

sfxhr_utf.htm

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
<html xmlns="http://www.w3.org/1999/xhtml">  
<head>  
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
<title>AJAX中文-UTF8版</title>  
<script type="text/javascript" src="SF.HTTP.xhr_utf.js" mce_src="SF.HTTP.xhr_utf.js"></script>  
</head>  
<body>  
<script type="text/javascript"><!--  
var url = 'ajax_utf.php';  
var charset = 'utf8';  
  
var method = 'post';  
//var method = 'get';  
  
SF.HTTP.xhr({  
    'charset':charset,  
    'url': url,  
    'type': method,  
    'params':{test:charset+' 北京 ' + method},  
    'success':function(ajaxObj)  
    {  
        alert(ajaxObj.responseText);  
    }  
});  
// --></script>  
</body>  
</html>  

SF.HTTP.xhr_utf.js

var SF =  
{  
    //HTTP 请求相关  
    HTTP:  
    {  
        /**兼容 GB2312 字符集的 Ajax 调用方法 
        变通是用 escape,提交的汉字会变成 %u9886%u5730 这样的,后端程序再处理成GB字符集的中文,见 ajax.php 中的 unescape 函数。 
        输入参数,JSON 格式对象 
        { 
        'url': url,     请求的 URL 
        'type': method, 提交方式,get 或 post,默认为 get 
        'charset':charset,  字符集,默认 utf-8 
        'params': 提交的参数,JSON 格式,如{var1:'北京', var2:'test'} 
        'success': 响应成功时的处理函数,传入参数是标准 XMLHttpRequest 对象 
        'fail': 请求失败时的处理函数,通常是在页面上给出提示,可以为空 
        'loading': 等行响应时的加载中函数,通常是在页面上给出提示,可以为空 
        } 
 
        */  
        xhr:function(json)  
        {  
            //取输入参数,以及赋默认值  
            var  
            url=json.url,  
            method=json.type || 'get',  
            params=json.params || {},  
            onComplete=json.success,  
            charset=json.charset || 'utf8',  
            onFailure=json.fail,  
            loading=json.loading;  
  
            var getHTTPObject = function() {  
                var xmlhttp = false;  
                if (window.XMLHttpRequest) {  
                    xmlhttp = new XMLHttpRequest();  
                } else if(window.ActiveXObject) {  
                    try {  
                        xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");  
                    } catch (e) {  
                        try {  
                            xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");  
                        } catch (e) {  
                            xmlhttp = false;  
                        }  
                    }  
                }  
                return xmlhttp;  
            };  
  
            if (loading)  
            {  
                loading();  
            }  
            var query = '';  
            for (var i in params)  
            {  
                var param = params[i];  
                if ('gb2312'==charset)  
                {  
                    param = escape(param);  
                }  
                //最终解决 IE 中 GET 方式参数值传递不灵,给 UTF-8 字符集时统一加上 encodeURIComponent  
                else  
                {  
                    param = encodeURIComponent(param);  
                }  
                query+= i + '='+ param + '&';  
            }  
            var XHR = getHTTPObject();  
  
            //XHR.setRequestHeader("charset","gb2312");  
            XHR.onreadystatechange = function() {  
                if (XHR.readyState == 4)    {  
                    if (XHR.status == 200 || XHR.status == 304) {  
                        if (onComplete)     {  
                            onComplete(XHR);  
                        }  
                    }  
                    else  
                    {  
                        if (onFailure)  {  
                            onFailure(XHR)  
                        };  
                    }  
                }  
            };  
            method = ('get' == method.toLowerCase()) ? 'get':'post';  
            if ('post'==method)  
            {  
                XHR.open(method, url, true);  
                XHR.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");  
                XHR.send(query);  
            }  
            else  
            {  
                url += '?'+ query + 'random='+Math.random();  
                XHR.open(method, url, true);  
                XHR.send(null);  
            }  
        }  
    }  
};  

ajax_utf.php

<?php  
$test = isset($_GET['test']) ? $_GET['test'] : $_POST['test'];  
//要让 IE 正常接收 UTF8 的数据,必须使用大写的“UTF-8”,而不能用小写!  
header("text/plain;charset=UTF-8");  
echo ($test);  

GB2312 变通方案

前后端文件本身统一都用ANSI编码。

HTML 文件使用声明:

<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />  

让 Ajax 对象不以默认的 UTF-8 编码发送数据,核心的变通是把参数值统一用 escape() 处理,汉字会变成 %u5317%u4EAC 这样的 Unicode 格式,从而浏览器会把它们当作西文数据,不再像普通汉字那样用 UTF-8 字符集再进行 URI 编码。即 SF.HTTP.xhr_utf.js 中的如下这行

param = escape(param);  

注意此时后台 PHP 程序接收到的请求数据是未编码的 Unicode 格式,需要转回成 GB2312 字符集的数据,使用PHP 程序中的 unescape() 函数即可。输出数据也必须是GB2312编码的,输出前加上声明:

header("Content-type: text/html; charset=gb2312");  

SF.HTTP.xhr() 方法使用说明请见方法注释及 HTML 范例。

不同字符集的范例包中 SF.HTTP.xhr.js 和 SF.HTTP.xhr_utf.js 内容完全相同,只是 SF.HTTP.xhr_utf.js 的文件编码是 UTF-8。建议使用 UTF-8 版时把前后全部文件都统一成 UTF-8 编码的文件,因为 IE 浏览器要求引用的外部文件也必须是UTF-8 编码。

以下是各文件完整的代码:

sfxhr.htm

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
<html xmlns="http://www.w3.org/1999/xhtml">  
<head>  
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />  
<title>AJAX中文-GB2312版</title>  
<script type="text/javascript" src="SF.HTTP.xhr.js" mce_src="SF.HTTP.xhr.js"></script>  
</head>  
<body>  
<script type="text/javascript"><!--  
var url = 'ajax.php';  
var method = 'post';  
var charset = 'gb2312';  
//var method = 'get';  
  
SF.HTTP.xhr({  
    'charset':charset,  
    'url': 'ajax.php',  
    'type': method,  
    'params':{test:charset+' 北京 ' + method},  
    'success':function(ajaxObj)  
    {  
        alert(ajaxObj.responseText);  
    }  
});  
// --></script>  
  
</body>  
</html>

SF.HTTP.xhr.js

var SF =  
{  
    //HTTP 请求相关  
    HTTP:  
    {  
        /**兼容 GB2312 字符集的 Ajax 调用方法 
        变通是用 escape,提交的汉字会变成 %u9886%u5730 这样的,后端程序再处理成GB字符集的中文,见 ajax.php 中的 unescape 函数。 
        输入参数,JSON 格式对象 
        { 
        'url': url,     请求的 URL 
        'type': method, 提交方式,get 或 post,默认为 get 
        'charset':charset,  字符集,默认 utf-8 
        'params': 提交的参数,JSON 格式,如{var1:'北京', var2:'test'} 
        'success': 响应成功时的处理函数,传入参数是标准 XMLHttpRequest 对象 
        'fail': 请求失败时的处理函数,通常是在页面上给出提示,可以为空 
        'loading': 等行响应时的加载中函数,通常是在页面上给出提示,可以为空 
        } 
 
        */  
        xhr:function(json)  
        {  
            //取输入参数,以及赋默认值  
            var  
            url=json.url,  
            method=json.type || 'get',  
            params=json.params || {},  
            onComplete=json.success,  
            charset=json.charset || 'utf8',  
            onFailure=json.fail,  
            loading=json.loading;  
  
            var getHTTPObject = function() {  
                var xmlhttp = false;  
                if (window.XMLHttpRequest) {  
                    xmlhttp = new XMLHttpRequest();  
                } else if(window.ActiveXObject) {  
                    try {  
                        xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");  
                    } catch (e) {  
                        try {  
                            xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");  
                        } catch (e) {  
                            xmlhttp = false;  
                        }  
                    }  
                }  
                return xmlhttp;  
            };  
  
            if (loading)  
            {  
                loading();  
            }  
            var query = '';  
            for (var i in params)  
            {  
                var param = params[i];  
                if ('gb2312'==charset)  
                {  
                    param = escape(param);  
                }  
                //最终解决 IE 中 GET 方式参数值传递不灵,给 UTF-8 字符集时统一加上 encodeURIComponent  
                else  
                {  
                    param = encodeURIComponent(param);  
                }  
                query+= i + '='+ param + '&';  
            }  
            var XHR = getHTTPObject();  
  
            //XHR.setRequestHeader("charset","gb2312");  
            XHR.onreadystatechange = function() {  
                if (XHR.readyState == 4)    {  
                    if (XHR.status == 200 || XHR.status == 304) {  
                        if (onComplete)     {  
                            onComplete(XHR);  
                        }  
                    }  
                    else  
                    {  
                        if (onFailure)  {  
                            onFailure(XHR)  
                        };  
                    }  
                }  
            };  
            method = ('get' == method.toLowerCase()) ? 'get':'post';  
            if ('post'==method)  
            {  
                XHR.open(method, url, true);  
                XHR.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");  
                XHR.send(query);  
            }  
            else  
            {  
                url += '?'+ query + 'random='+Math.random();  
                XHR.open(method, url, true);  
                XHR.send(null);  
            }  
        }  
    }  
};

ajax.php

<?php  
//如果输入参数不是 unicode 格式的值,则会原样返回。  
function unescape($str) {  
    $str = rawurldecode($str);  
    preg_match_all("/(?:%u.{4})|&#x.{4};|&#/d+;|.+/U",$str,$r);  
    $ar = $r[0];  
    //print_r($ar);  
    foreach($ar as $k=>$v) {  
        if(substr($v,0,2) == "%u")  
        $ar[$k] = iconv("UCS-2","GB2312",pack("H4",substr($v,-4)));  
        elseif(substr($v,0,3) == "&#x")  
        $ar[$k] = iconv("UCS-2","GB2312",pack("H4",substr($v,3,-1)));  
        elseif(substr($v,0,2) == "&#") {  
            echo substr($v,2,-1)."<br>";  
            $ar[$k] = iconv("UCS-2","GB2312",pack("n",substr($v,2,-1)));  
        }  
    }  
    return join("",$ar);  
}  
  
$test = isset($_GET['test']) ? $_GET['test'] : $_POST['test'];  
//为确保输出内容为指定字符集,显式声明一下。要输出 GB2312 字符集内容时,  
header("Content-type: text/html; charset=gb2312");  
echo unescape($test);