2012-02-10
Tags: javascript , 程式語言 , jquery
要用JavaScript實作Ping程式,用jQuery裡的ajax功能來實作是我想到最簡單的方式(自己用JavaScript純手工打造也ok啦,但是可以用jQuery爽爽做事就不想自己當苦行僧了...:P)。然後...我自己在實作時遇到下面所提的問題。
JavaScript基於同源策略(Same-origin policy),"
一般而言
"位於不同domain的網頁是無法相互叫用的(e.g. 放在test1.mydomain.com的JavaScript不能執行test2.mydomain.com的JavaScript)。 不給相互叫用的原因是基於安全性的考量,怕會發生
XSS(Cross-site scripting)的問題。
用JavaScript去實作Ping一定會違背同源策略,所以要想辦法突破這個Cross-Domain Requests的難題。相對的解法有儿種,可以參考
這篇文章。話說回來,看完後應該會覺的都很麻煩,但是現行也沒什麼其它的選擇就是了。
最後我解決這問題的方式是用了JSONP(相關說明:
其一、
其二)的方式來處理。因為<script></script>裡面
src屬性指到的網址所包含的內容不受同源策略限制(這就是前面那段"
一般而言
"裡的例外啦),所以JSONP的方法才能成功運作。
因為用的是JSONP的方式,所以你預期ServerSide一定會吐回一個JavaScript格式的資料,但是這在Ping程式上是一定辦不到的。因為ServerSide可不是你管的,你無權在ServerSide上加入任何Server端程式碼(e.g. JSP、PHP、ASP.Net...etc)。不過沒關系,反正只要ServerSide能成功吐回任何資料,Ping程式就有辦法判斷執行的結果(Ping是否成功、執行花了多久...etc),吐回資料的內容不是JavaScript格式只是導致jQuery在"
成功
"取得資料後(指http status code為200,並拿到回傳的資料),每次都會發生parsererror。發生parsererror的原因是由於ServerSide執行成功時,丟回來的資料會是html格式,所以jQuery在接手處理後一定會發生parsererror,這其實是我們預期中的狀況。
有了解法後,就可以開始實作了,下面是用jQuery實作出來的解法。
ping.js
$.ping = function(url,callBack)
{
var requestTime;
function appendHttpPrefix(url){
//保證url帶http://
var strReg="^((https|http)?://){1}";
var re=new RegExp(strReg);
return re.test(url)?url:"http://"+url;
}
$.ajax({
url: appendHttpPrefix(url),
type: "GET",
dataType: "jsonp", //設成jsonp來解決cross-domain requests的問題
timeout: 5000, //超過5秒沒回應就timeout
cache: false, //不保留cache
beforeSend: function(){
requestTime = new Date().getTime();
},
complete: function(jqXHR, textStatus){
var responseTime = new Date().getTime();
var ackTime = responseTime - requestTime;
var status;
//因為dataType用jsonp格式,但是Server端未針對這部份進行處理,所以執行成功時
//必定會發生"parsererror"(因為回傳的資料格式不為JavaScript,所以會"parsererror")。
//此時將需將status手動改回"success"
if(textStatus == "parsererror"){
status = "success";
}
else{
status = textStatus;
}
callBack({
url: url,
ackTime: ackTime,
status: status
});
}
});
};
<html>
<head>
<script language="javascript" src="jquery-1.7.1.min.js"></script>
<script language="javascript" src="ping.js"></script>
<script>
$(function(){
var timerId;
var isStopPing = false;
$("#pingStart").click(function(){
$(this).attr("disabled", true);
$("#pingStop").attr("disabled", false);
$.ping($("#webSiteUrl").val(),
function(pingResult){
timerId = setInterval(function(){
if(isStopPing == true){
clearInterval(timerId);
isStopPing = false;
return;
}
if(pingResult){
$("#pingResultMsg").append("{ url:" + pingResult.url + " ,ackTime:" + pingResult.ackTime + " ,status:" + pingResult.status + " }<br>");
clearInterval(timerId);
$("#pingStart").trigger("click");
}
},1000);
}
);
});
$("#pingStop").click(function(){
isStopPing = true;
$("#pingStart").attr("disabled", false);
$(this).attr("disabled", true);
});
$("#clearPingResultMsg").click(function(){
$("#pingResultMsg").html("");
});
});
</script>
</head>
<body>
<div>
WebSiteURL:<input type="text" size="50" id="webSiteUrl">
</div>
<div>
<input type="button" id="pingStart" value="PingStart">
<input type="button" id="pingStop" value="PingStop" disabled="disabled">
<input type="button" id="clearPingResultMsg" value="ClearPingResultMsg">
</div>
<div id="pingResultMsg"></div>
</body>
</html>