簡介
符合Web2.0特徵的衆多網站一個明顯的特色就是採用Ajax。Ajax提供了在後臺提交請求訪問數據的功能。其實現主要使用的是XMLHttpRequest函數,這個函數容許客戶端的Javascript
發送到服務器端的HTTP請求並得到返回數據。Ajax同時也是目前衆多的Mashup背後的驅動力量,他們都利用Ajax來聚合不一樣來源的信息。
理解同源策略的限制
同源策略是指阻止代碼得到或者更改從另外一個域名下得到的文件或者信息。也就是說咱們的請求地址必須和當前網站的地指相同。同源策略經過隔離來實現對資源的保護。這個策略的歷史很是悠久
從Netscape Navigator 2.0時代就開始了。
解決這個限制的一個相對簡單的辦法就是在服務器端發送請求,服務器充當一個到達第三方資源的代理中繼。雖然是用普遍可是這個方法卻不夠靈活。
另外一個辦法就是使用框架(frames),將第三方站點的資源包含進來,可是包含進來的資源一樣要受到同源策略的限制。
有一個很巧妙的辦法就是在頁面中使用動態代碼元素,代碼的源指向服務地址並在本身的代碼中加載數據。當這些代碼加載執行的時候,同源策略就不會起到限制。可是若是代碼試圖下載文件的時候
執行仍是會失敗,幸運的是,咱們能夠使用JSON(JavaScript Object Notation)來改進這個應用。
JSON和JSONP
與XML相比,JSON是一個輕量級的數據交換格式。JSON對於JavaScript開發人員充滿魅力的緣由在於JSON自己就是Javascript中的對象。
例如一個ticker對象
var ticker = {symbol:'IBM',price:100}
而JSON串就是 {symbol:'IBM',price:100}
這樣咱們就能夠在函數的參數中傳遞JSON數據。咱們很容易掌握在函數中使用動態的JSON參數數據,可是咱們的目的並非這個。
經過使咱們的函數可以加載動態的JSON數據,咱們就可以處理動態的數據,這項技術叫作 Dynamic Javascript Insertion。
咱們看下面的例子
index.html中
<script type="text/javascript">
function showPrice(data){
alert("Symbol:" + data.symbol + ", Price:" + data.price);
}
var url = "ticker.js"; //Outer JS URL
var script = document.createElement('script');
script.setAttribute('src', url);
//load javascript
document.getElementsByTagName('head')[0].appendChild(script);
</script>
ticker.js中
var data = {symbol:'IBM', price:100};
showPrice(data);
上面的代碼經過動態加入Javascript代碼,來執行函數加載數據。
正如以前提到過的,同源策略對於動態插入的代碼不適用。也就是你能夠從不一樣的域中加載代碼,來執行在他們代碼中的JSON數據。
這就是JSONP(JSON with Padding)。注意,使用這種方法時,你必須在頁面中定義回調函數,就像上例中的showPrice同樣。
咱們一般所說的JSONP服務(遠程JSON服務),實際上就是一種擴展的支持在用戶定義函數中包含返回數據的能力。這種方法依賴於必須接受一個回調函數的名字做爲參數。
而後執行這個函數,處理JSON數據,並顯示在客戶頁面上。
JQuery的JSONP支持
從JQery 1.2之後,就開始支持JSONP的調用。在另外的一個域名中指定好回調函數名稱,你就能夠用下面的形式來就加載JSON數據。
url?callback=?
示例:
jQuery.getJSON(url + "&callbak=?", function(data){
alert("Symbol:" + data.symbol + ", Price:" + data.price);
});
jquery會在window對象中加載一個全局的函數,當代碼插入時函數執行,執行完畢後就會被移除。同時jquery還對非跨域的請求進行了優化,若是這個請求是在同一個域名下
那麼他就會像正常的Ajax請求同樣工做。
上例中咱們在動態插入到頁面的代碼中使用了靜態的json數據,雖然完成了依次JSONP返回,但仍不是JSONP服務,由於不支持在URL中定義回調函數名稱。下面是一個將其變成JSONP服務的一個方法
服務器端使用PHP。
首先咱們來定義接口的規範,就像這樣:http://www.mydomain.com/jsonp/ticker?symbol=IBM&callback=showPrice
symbol是請求條件,callback是回調函數名稱。
在頁面文件中,咱們使用JQuery的支持:
//JQuery JSONP Support
var url = "http://www.mydomain.com/api/suggest.php?symbol=IBM&callback=?";
jQuery.getJSON(url, function(data){
alert("Symbol:" + data.symbol + ", Price:" + data.price);
});
在suggest.php中
$jsondata = "{symbol:'IBM', price:120}";
echo $_GET['callback'].'('.$jsondata.')';
再舉個.NET webservice 的例子javascript
客戶端php
$.getJSON(html
"http://192.168.0.66/services/WebService1.asmx/ws?callback=?",java
{ name: "ff", time: "2pm" },jquery
function(data) { alert(decodeURI(data.msg)) }web
);json
服務器端api
[WebMethod]
public void ws(string name,string time) {跨域
HttpRequest Request = HttpContext.Current.Request;
string callback = Request["callback"];
HttpResponse Response = HttpContext.Current.Response;
Response.Write(callback + "({msg:'this is"+name+"jsonp'})");
Response.End();
}安全
如今,若是咱們想製做一些mashup,或者將第三方的資源整合到一個頁面中,咱們就很容易想到JSONP的解決方法了。
現有的JSONP服務 既然咱們已經知道如何使用JSONP,那麼咱們也就能夠使用一些現有的JSONP服務了,下面是一些例子: Digg API:http://services.digg.com/stories/top?appkey=http%3A%2F%2Fmashup.com&type=javascript&callback=? Geonames API:http://www.geonames.org/postalCodeLookupJSON?postalcode=10504&country=US&callback=? Flickr API:http://api.flickr.com/services/feeds/photos_public.gne?tags=cat&tagmode=any&format=json&jsoncallback=? 注意: JSONP是一個很是強大的構建mashup的方法,但是不是一個解決跨域訪問問題的萬能藥。它也有一些缺點 第一也是最重要的:JSONP不提供錯誤處理。若是動態插入的代碼正常運行,你能夠獲得返回,可是若是失敗了,那麼什麼都不會發生。你沒法得到一個404的錯誤,也不能取消這個請求 另一個重要的缺點是若是使用了不信任的服務會形成很大的安全隱患