為一個使用BIG5編碼的網站寫一小段AJAX Script滿足需求,結果踢到了鐵板。

使用$.get()或$.post()取得後端網頁程式執行內容是很普遍的技巧,但若網頁採BIG5編碼而非UTF-8時,會衍生額外議題。

以下面的網頁為例,我們在按鈕click()事件中使用$.get(location.href)取回網頁本身內容再alert出來,但有個重點--網頁記得要存成為BIG5編碼。(不知如何指定檔案編碼的朋友,可參考文末附註)

<!DOCTYPE html>
<html>
<head runat="server">
    <meta http-equiv="Content-Type" content="text/html; charset=big5" />
    <title>中文標題測試</title>
    <!-- 中文註解測試 -->
    <script type="text/javascript" 
        src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.6.1.js"> </script>
    <script type="text/javascript">
        $(function () {
            $.ajaxSetup({
                beforeSend: function (xhr) {
                    xhr.overrideMimeType("text/html; charset=big5");
                }
            });
            $("#b").click(function () {
                $.get(location.href, {}, function (resp) {
                    alert(resp.substr(0, 250));
                });
            });
        });
    </script>
</head>
<body>
    <div>測試</div>
    <input type="button" id="b" value="Test" />
</body>
</html>

若檔案編碼儲存正確,瀏覽器檢視時可發現網頁被解讀為Big5。按下按鈕,程式在Firefox、Chrome下執行正常,但在IE下中文內容無法正確解讀:

接著,我們將overrideMimeType那一段拿掉,這下子連Firefox執行都會出現亂碼:

問題在哪裡? 當我們執行$.ajax()/$.get()/$.post()時,背後會透過XmlHttpRequest物件(XHR)與網站溝通,除非網站程式透過Response Header指定ContentType = "text/html; charset=big5”,否則XHR預設會將網站傳回內容視為UTF-8編碼。在這個案例中,IIS在傳回HTML時無從指定ContentType Header,Chrome的XHR似乎可由HTML內容中的ContentType標籤(或是由二進位內容自動識別?)切換使用Big5編碼;Firefox的XHR支援overrideMimeType功能,可透過程式碼強迫指定XHR用什麼ContentType解析接收到的內容;只剩下IE既無法自動識別也不支援overrideMimeType,無能為力。

本以為問題無解,爬文時發現對岸有網友想出天才型的絕妙解法: 在Javascript中借用VBScript MidB()、CHR(),巧妙地將ResponseBody的二進位內容轉碼成UTF-8相容!! (參考來源: http://ajax.cnrui.cn/article/1/2/2006/20060714246.shtml 我找不到原始出處,好想向原作者致敬!)

函數原本用來處理GB2312編碼,亦可直接拿來解決BIG5問題,不需修改。程式範例如下:

<!DOCTYPE html>
<html>
<head runat="server">
    <meta http-equiv="Content-Type" content="text/html; charset=big5" />
    <title>中文標題測試</title>
    <!-- 中文註解測試 -->
    <script type="text/javascript" 
        src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.6.1.js"></xscript>
    <script src="jquery-1.6.2.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(function () {
            $("#b").click(function () {
                var xhr = new XMLHttpRequest();
                xhr.open("GET", location.href, true);
                //如果IE有支援overrideMimeType的話,事情就簡單多了,只可惜...
                if (xhr.overrideMimeType)
                    xhr.overrideMimeType('text/html; charset=big5');
                xhr.onreadystatechange = function () {
                    if (xhr.readyState == 4) {
                        alert(xhr.responseText.substr(0, 250));
                        if (xhr.responseBody)
                            alert(gb2utf8(xhr.responseBody).substr(0, 250));
                    }
                }
                xhr.send();
            });
        });
        function gb2utf8(data) {
            var glbEncode = [];
            gb2utf8_data = data;
            execScript("gb2utf8_data = MidB(gb2utf8_data, 1)", "VBScript");
            var t = escape(gb2utf8_data).replace(/%u/g, "")
.replace(/(.{2})(.{2})/g, "%$2%$1").replace(/%([A-Z].)%(.{2})/g, "@$1$2");
            t = t.split("@");
            var i = 0, j = t.length, k;
            while (++i < j) {
                k = t[i].substring(0, 4);
                if (!glbEncode[k]) {
                    gb2utf8_char = eval("0x" + k);
                    execScript("gb2utf8_char = Chr(gb2utf8_char)", "VBScript");
                    glbEncode[k] = escape(gb2utf8_char).substring(1, 6);
                }
                t[i] = glbEncode[k] + t[i].substring(4);
            }
            gb2utf8_data = gb2utf8_char = null;
            return unescape(t.join("%"));             
        }
    </script>
</head>
<body>
    <div>測試</div>
    <input type="button" id="b" value="Test" />
</body>
</html>

經測試,這下子終於讓IE XHR也可以解析BIG5內容囉~~

爬文時發現一篇有趣的Mail討論,John Resig發現IE不支援overrideMimeType時也楞了一下。 XD

 

【附註】可能有朋友不知何將檔案以指定編碼儲存,這裡介紹幾種做法:

1.Visual Studio另存新檔時指定編碼格式:

2.使用文字編輯軟體轉換編碼
例如: Notepad++ (另外,以前也介紹過UltraEdit, EmEditor)
Windows內建的記事本(Notepad)也支援


Comments

Be the first to post a comment

Post a comment