Ajax跨域工具: Modello.ajax
問題
Ajax是個好東西,但使用起來卻不是那麼方便。問題總結如下:
- 在各種瀏覽器上的建立方式和使用方法不一致
- 各個瀏覽器對響應的緩衝策略有所不同
- 瀏覽器存在跨域擷取限制
前兩個問題可以通過封裝 XMLHTTPRequest 對象來解決,第三個問題的解決方案有很多中,相容性和移植性比較好的就是在本網域服務器上放置一個中轉 proxy 。Modello.ajax 就是提供這套解決方案的工具集。
安裝
下載Modello 和 Mdello.ajax
解壓並將 modello.js, modello.ajax.js, jsproxy.php 這三個檔案放到你的伺服器任意文檔目錄中
在 html 頁面中包含 modello.js 和 modello.ajax.js 這兩個指令檔
urlget 方法
Modello.ajax 使用起來非常的簡單,請看下面例子:
程式碼// 設定跨域中轉 proxy 路徑
Define('URLGET_PROXY', '/jsproxy.php');
// 強大的 urlget 方法
var urlget = Class.get('modello.ajax.Urllib').urlget;
var url = '…';
// 同步 GET 方法擷取
var response = urlget(url);
// 同步 POST 方法擷取
var data = '…';
var response = urlget(url, data);
// 非同步 POST 方法擷取
var callback = function (response) {
// …
}
var ret = urlget(url, data, callback);
// 佈建要求頭部
var headers = ["User-Agent: Modello.ajax's urlget"];
var ret = urlget(url, data, callback, headers);
// 使用命名通道
var chunnel = '…';
var ret = urlget(url, data, callback, headers, chunnel);
// 使用 Response 對象
if (response.getStatus() == 200) {
alert(response.getText());
}// 設定跨域中轉 proxy 路徑
Define('URLGET_PROXY', '/jsproxy.php');
// 強大的 urlget 方法
var urlget = Class.get('modello.ajax.Urllib').urlget;
var url = '…';
// 同步 GET 方法擷取
var response = urlget(url);
// 同步 POST 方法擷取
var data = '…';
var response = urlget(url, data);
// 非同步 POST 方法擷取
var callback = function (response) {
// …
}
var ret = urlget(url, data, callback);
// 佈建要求頭部
var headers = ["User-Agent: Modello.ajax's urlget"];
var ret = urlget(url, data, callback, headers);
// 使用命名通道
var chunnel = '…';
var ret = urlget(url, data, callback, headers, chunnel);
// 使用 Response 對象
if (response.getStatus() == 200) {
alert(response.getText());
}
urlget 各個參數的解釋如下:
url:目標資源的 URL 地址。
Data:POST 資料。如果 data 為空白,則使用 GET 方法擷取。
Callback:非同步擷取回呼函數。如果 callback 為空白,則使用同步擷取。
Headers:附加要求標頭部。這是一個數組,每一項為字串,設定一行頭部,字串末尾不可以帶斷行符號換行。
Chunnel:命名通道。用於重用某個串連通道。
Urlget 的傳回值:
如果是同步擷取,成功返回 Response 對象,失敗返回 false。如果是非同步擷取,成功返回 true,並且在擷取後調用回呼函數,失敗返回 false。如果指定了命名通道,但該通道正在被其它請求佔用,同步、非同步都統一返回 false。
回呼函數的參數:
response:Response 對象。
Chunnel:調用時指定的命名通道。
Response 對象
Response 對象用於訪問響應的各個資料項目。它提供介面如下:
response.getStatus(); // HTTP 響應碼(整數)
response.getStatusText(); // 響應碼的字面解釋
response.getHeader(key); // 由 key 指定的響應的頭部資料
response.getAllHeaders(); // 響應的所有頭部資料(不包含狀態行)
response.getRawHeader(); // 響應的原樣頭部資料(包含狀態行)
response.getText(); // 響應的體部資料
response.getXML(); // 響應的體部資料格式化為 Xml Document 對象response.getStatus(); // HTTP 響應碼(整數)
response.getStatusText(); // 響應碼的字面解釋
response.getHeader(key); // 由 key 指定的響應的頭部資料
response.getAllHeaders(); // 響應的所有頭部資料(不包含狀態行)
response.getRawHeader(); // 響應的原樣頭部資料(包含狀態行)
response.getText(); // 響應的體部資料
response.getXML(); // 響應的體部資料格式化為 Xml Document 對象
大部分情況下,使用 urlget 函數足可以應付,並且它是可以跨瀏覽器,跨域使用的。如果你想做一些更底層的操作,Modello.ajax 為你提供兩個跨瀏覽器使用的基類:Connection 和 Request
Connection 類
這是一個靜態類,提供跨瀏覽器的方法返回一個 XMLHTTPRequest 對象。使用方法如下:
程式碼/*
* 成功返回一個跨瀏覽器版本的 XMLHTTPRequest 對象,
* 失敗返回 null。
*/
var conn = Class.get('modello.ajax.Connection').get();/*
* 成功返回一個跨瀏覽器版本的 XMLHTTPRequest 對象,
* 失敗返回 null。
*/
var conn = Class.get('modello.ajax.Connection').get();
Request 類
這是對 XMLHTTPRequest 對象的封裝,提供更加易用的介面並解決瀏覽器對響應緩衝的問題,但不具備跨域擷取功能。Request 提供的屬性和方法如下:
/*
* 類的路徑
*/
var Request = Class.get('modello.ajax.Request');
/*
* 建立執行個體
* url, method, data 均為選擇性參數
*/
var request = new Request([url[, method[, data]]]);
/*
* 設定 URL
*/
request.setURL(url);
/*
* 設定擷取方法。目前支援:GET, POST, HEAD
*/
request.setMethod(method);
/*
* 設定擷取方法。目前支援:GET, POST, HEAD
*/
request.setData(data);
/*
* 設定回呼函數
* 回呼函數的原型為:
* var callback = function (response) {};
*/
request.setHandler(handler);
/*
* 佈建要求頭部
*/
request.setHeader(key, value);
/*
* 增加要求標頭部
*/
request.addHeader(header);
/*
* 發送請求
* async 為 true,使用非同步方式
* 預設使用同步方式
* 調用成功,同步方式返回 response 對象,非同步方式返回 true
* 調用失敗,統一返回 false
*/
request.open([async]);
/*
* 查詢當前請求的狀態
* 返回一個字串描述,可能為:
* Uninitialized:未初始化
* Loading:初始化
* Loaded:發送資料
* Interactive:資料傳送中
* Complete:完成
*/
request.getState();
/*
* 返回當前使用的 Connection 對象
*/
request.getConnection();
/*
* 返回 Response 對象
* 如果當前的請求狀態不為 Complete,返回 null
*/
request.getResponse();
/*
* 中止當前請求
*/
request.abort();
/*
* 清理所有要求標頭部
*/
request.reset();
/*
* 除了上面的方法,還可以對 Request 對象設定事件處理函數
* 總共有下面幾種事件
*/
request.onException = function() {};
request.onLoading = function() {};
request.onLoaded = function() {};
request.onInteractive = function() {};
request.onComplete = function() {};/*
* 類的路徑
*/
var Request = Class.get('modello.ajax.Request');
/*
* 建立執行個體
* url, method, data 均為選擇性參數
*/
var request = new Request([url[, method[, data]]]);
/*
* 設定 URL
*/
request.setURL(url);
/*
* 設定擷取方法。目前支援:GET, POST, HEAD
*/
request.setMethod(method);
/*
* 設定擷取方法。目前支援:GET, POST, HEAD
*/
request.setData(data);
/*
* 設定回呼函數
* 回呼函數的原型為:
* var callback = function (response) {};
*/
request.setHandler(handler);
/*
* 佈建要求頭部
*/
request.setHeader(key, value);
/*
* 增加要求標頭部
*/
request.addHeader(header);
/*
* 發送請求
* async 為 true,使用非同步方式
* 預設使用同步方式
* 調用成功,同步方式返回 response 對象,非同步方式返回 true
* 調用失敗,統一返回 false
*/
request.open([async]);
/*
* 查詢當前請求的狀態
* 返回一個字串描述,可能為:
* Uninitialized:未初始化
* Loading:初始化
* Loaded:發送資料
* Interactive:資料傳送中
* Complete:完成
*/
request.getState();
/*
* 返回當前使用的 Connection 對象
*/
request.getConnection();
/*
* 返回 Response 對象
* 如果當前的請求狀態不為 Complete,返回 null
*/
request.getResponse();
/*
* 中止當前請求
*/
request.abort();
/*
* 清理所有要求標頭部
*/
request.reset();
/*
* 除了上面的方法,還可以對 Request 對象設定事件處理函數
* 總共有下面幾種事件
*/
request.onException = function() {};
request.onLoading = function() {};
request.onLoaded = function() {};
request.onInteractive = function() {};
request.onComplete = function() {};
jsproxy
對於跨域調用,Modello.ajax 採用在本網域服務器設定一個中轉 proxy 的方式。使用 proxy 方式可以不用對個別瀏覽器進行特殊設定,不用依賴具體的伺服器,並且具備擴充能力等優點。隨 Modello.ajax 工具集提供的 proxy 用 php 寫成,可運行 php 的伺服器都可以安裝。Proxy 也可以用其它語言編寫,Modello.ajax 有計劃在後續版本中提供 python 版的 jsproxy。下面來描述 jsproxy 的設計,有需要的朋友可以參考來實現其它語言版本的 jsproxy。
Jsproxy 接收三個 POST 參數:url, data, headers。Url 為目標資源的URL地址;data 為POST資料,如果為空白則使用 GET 方法擷取資源;headers 附加的要求標頭部資料。Jsproxy 根據這些參數去擷取目標資源,然後將收到的回應標頭部和響應體部全部轉寄給要求者。Jsproxy 收到的參數是由 Modello.ajax 發出的,字元集為 UTF-8,處理的時候要注意這點。Jsproxy 擷取到的響應的字元集有很多種可能的,在轉寄響應之前 jsproxy 應該自動檢測出當前響應的字元集,並在轉寄的回應標頭部指明。如果忽律這個步驟,要求者收到的響應有可能是亂碼。
Urlparse, urljoin 函數
urlparse, urljoin 這樣的 URL 處理函數在其它指令碼語言中很常見,但在 JavaScript 中卻沒有。Modello.ajax 提供了這兩個函數,前面提到的 urlget 函數內部就使用了這兩個函數。下面來解釋他們的用法:
程式碼/*
* urlparse:URL 分析函數
*/
var url = 'http://user:pass@host:port/path?query#flagment';
var ret = Class.get('modello.ajax.Urllib').urlparse(url);
// 這時候
// ret.user == 'user'
// ret.pass == 'pass'
// ret.host == 'host'
// ret.post == 'post',預設為 80
// ret.path == 'path',以 '/' 開頭
// ret.query == 'query'
// ret.flagment == 'flagment'
/*
* urljoin:合并兩個 URL
*/
var url1 = 'http://www.example.com/about/about.html';
var url2 = '/index.html';
var url = Class.get('modello.ajax.Urllib').urljoin(url1, url2);
// 這時候
// url == 'http://www.example.com/index.html'/*
* urlparse:URL 分析函數
*/
var url = 'http://user:pass@host:port/path?query#flagment';
var ret = Class.get('modello.ajax.Urllib').urlparse(url);
// 這時候
// ret.user == 'user'
// ret.pass == 'pass'
// ret.host == 'host'
// ret.post == 'post',預設為 80
// ret.path == 'path',以 '/' 開頭
// ret.query == 'query'
// ret.flagment == 'flagment'
/*
* urljoin:合并兩個 URL
*/
var url1 = 'http://www.example.com/about/about.html';
var url2 = '/index.html';
var url = Class.get('modello.ajax.Urllib').urljoin(url1, url2);
// 這時候
// url == 'http://www.example.com/index.html'