不過, 因為網頁瀏覽器的安全性設定問題, 所以使用 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, 那就多加一點功能, 看起來也比較有價值.
沒有留言:
張貼留言