不過, 因為網頁瀏覽器的安全性設定問題, 所以使用 AJAX 呼叫的頁面都是在同網域頁面.
也就是說, 呼叫的頁面是在開發者能掌控的範圍 (包括可修改).
因此, 許多網頁對於 AJAX 所呼叫的頁面傳回亂碼的解答, 就會是建議開發者去修改被呼叫頁面的 charset.
例如以下三種語言的修改法:
- ASP / ASP.Net:
Response.Charse="big5"
- PHP:
header("Content-Type:text/html;charset=big5"); - JSP:
response.setHeader("Charset","big5");
由於是在本機執行, 所以權限上可以到外站去讀取網頁資料.
在此情況下, 外站的編碼就不是開發者能去控制的, 僅能讀回來後自行轉碼.
以下將使用 Track Anywhere 這個網站的 IP/Domain 網域查詢, 說明 ADO Stream 的轉碼.
JavaScript 的程式片段如下:
<html>
<head>
<meta http-equiv="Content-Language" content="ZH-TW">
<meta http-equiv="Content-Type" content="text/html; charset=utf8">
<title>IP/Domain查詢程式</title>
<HTA:APPLICATION ID="oHTA" INNERBORDER="no" NAVIGABLE="yes"
SCROLL="no" Border="Thin" MAXIMIZEBUTTON="no"/>
<script type="text/javascript">
window.resizeTo(800, 600);
var objXmlHttp = null;
function DoQuery()
{
//設定使用者輸入的IP或Domain Name
var strInput = document.getElementById("txtInput").value;
if (window.XMLHttpRequest)
{// code for IE7, Firefox, Opera, etc.
objXmlHttp = new XMLHttpRequest();
}
else if (window.ActiveXObject)
{// code for IE6, IE5
objXmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
if (objXmlHttp==null)
{
alert("未支援XMLHTTP");
return;
}
//設定此查詢的處理函式
objXmlHttp.onreadystatechange = GetQueryResponse;
//送出查詢
objXmlHttp.open("POST",
"http://tracker.derekr.com//cgi-bin/cgiwrap/tracker/services/whois.cgi", true);
//送出查詢的參數
objXmlHttp.send("IP=" + strInput);
}
function GetQueryResponse()
{
if (objXmlHttp.readyState == 4)
{
var objStream = new ActiveXObject("ADODB.Stream");
objStream.Mode = 3;//Read/write
objStream.Type = 1;//Binary
objStream.Open();//開啟Stream Object
objStream.Position = 0;//設定起始位置
//將查詢結果的Binary資料寫入至Stream Object
objStream.Write(objXmlHttp.responseBody);
objStream.Position = 0;//再設定一次起始位置
objStream.Type = 2;//把Type調整至純文字
objStream.Charset = "Big5";//設定輸出的charset是big5
//移除掉換行符號(方便後續的字串處理)
var strResp = objStream.ReadText().replace(/[\r\n]/g, "");
objStream.Close();//關閉Stream Object
//只取結果<center></center>中的資料
var regResult = /<center[^>]*>.+<\/center>/gm;
//顯示結果
document.getElementById("divOutput").innerHTML = regResult.exec(strResp);
}
}
</script>
</head>
<body style="text-align:center;width:100%">
IP/Domain:<input id="txtInput" value="192.168.0.1" />
<input type="button" value="查詢" onclick="DoQuery()" />
<hr/>
<div id="divOutput" >
</div>
</body>
</html>
以下是程式的說明 (如果上述的程式註解看不懂): - Line 41: 先把 Stream 物件的 Mode 設定至 Read / Write. (可參考: ConnectModeEnum)
- Line 42: 將 Stream 物件的 Type 設定至 Binary 的資料類型. (可參考: StreamTypeEnum)
- Line 43: 開啟Stream物件,開始進行資料寫入的動作.
- Line 46: 為 step2 已經設定是 Binary 的資料類型, 所以這邊寫入的是 responseBody, 而不是 responseText.
至於為什麼要用 responseBody, 而不用 responseText, 其實各位可以試試看.
我的測試結果是: 用 responseBody 去轉碼至 Big5 可以成功, responseText 去轉碼還是亂碼. 所以建議用 Binary 的資料去轉. - Line 47: 因為先前已經有寫入資料至 Stream 物件中, 所以要讀資料前, 先把 Position 再設定至 0, 也就是設定至資料的起始位置.
- Line 48: 將 Stream 物件的 Type 設定至 Text 的資料類型.
- Line 49: 將 Stream 物件的 Charset 設定至中文的 Big5.
- Line 51: 透過 ReadText() 函式, 轉碼後的文字讀出來. 這邊多做了一個移除換行符號的處理, 為的是方便後續 Regexp 處理查詢結果.
- Line 52: 資料讀完後, 記得將 Stream 物件關閉. (養成有開有關的好習慣)
- Line 54 & 56: 因為查詢結果中包括了整個 html 的程式碼, 而我只需要其中 <center> 中的資料. 所以就弄了個 Regexp 將我要的資料抽出來.
如果有人想要查詢結果 <table> 中的資料, 把 center 改成 table 就可以了.
- 關於 ADO Stream Object 的參考, 可至: http://www.w3schools.com/ado/ado_ref_stream.asp 得到相關說明.
- 編碼上要注意字集的大小, 不要大字集轉小字集, 因為會衍生對不到字碼的問題.
不然介面上只允許一筆 IP/Domain Name 的輸入, 不就跟使用瀏覽器到網站上查詢一樣嗎? XD
既然要改成 HTML Application, 那就多加一點功能, 看起來也比較有價值.
沒有留言:
張貼留言