使用XHR下載BIG5編碼內容
0 |
為一個使用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