首先,需要明確記住的是,jsonp不是ajax的一種特例,而是使用動態script來獲取數據的一種方式。
原理
由于同源策略,一般來說位于 server1.example.com的網頁無法與不是 server1.example.com 的服務器溝通, 而 HTML的 <script>
元素是個例外,利用這個策略,可以實現跨域獲取數據的功能。
所以,我們只要構建一個<script>
元素,然后將 src
屬性賦值成我們請求資料的地址即可(參數適用get方式進行拼接),比如:
<script type="text/javascript"
src="http://server2.example.com/userlist?userId=1823&callback=sayHello">
</script>
瀏覽器請求這個資源,服務器端進行一些特殊的處理,給瀏覽器返回如下所示的資源。
sayHello({
'userId' : 1823,
'name' : 'stackbox'
})
即全局運行了一個sayHello函數,參數為獲取的json數據。
jQuery內置提供的jsonp功能,最簡單的使用方式如下:
jQuery.getJSON(url+"&callback=?", function(data) {
alert("Symbol: " + data.symbol + ", Price: " + data.price);
});
此時jQuery會生成一個命名隨機的callback方法, 比如 jQuery18308848262811079621_1393981029347,然后會
將這個函數附加到全局window,這樣返回資源的時候就能調用這個函數了。
也可以指定自己的callback名,比如:
$.ajax({
url:"http://localhost:20002/MyService.ashx?callback=?",
dataType:"jsonp",
jsonpCallback:"person",
success:function(data){
alert(data.name + " is a a" + data.sex);
}
});
除了使用 $.ajax,也可以使用 $.ajaxSetup對請求進行設置。
示例
備注
JSONP是一個非標準的規范,其優點在于瀏覽器兼容性,而且由于發展
的比較早目前有大量基于JSONP的api(Yahoo,Twitter, etc) 和庫(jQUery, YUI)
它的缺點也很明顯:
- 使得rest風格的api不再那么優雅
- 安全問題
- 與跨域的接口交互困難,無法post,無法直接給接口傳一個json(雖然可以URLEncode成一個參數,但是比較丑陋)
- 調試復雜,具體參見 這篇文章
而且,解決跨域問題的方式不止有JSONP這一種,還有 Cross-Origin Resource Sharing (CORS) 和 Proxy兩種。
- CORS的關鍵在于: XMLHttpRequest 在Level 2時新增了跨域訪問的功能,需要在服務器端設置一些特殊header,兼容性你懂得。
- Proxy方式就是: 使用apache/Nginx將另外一個site的接口映射到同源的URL下,簡單暴力。缺點在于每次新的api都要修改proxy的配置。
后記
資料來源:
- http://zh.wikipedia.org/wiki/JSONP
- http://blog.csdn.net/patern_pan/article/details/7588755
- http://forum.jquery.com/topic/jsonp-and-randomly-generated-callback-function
- http://stackoverflow.com/questions/22186703/modifying-jquery-jsonp-callback-function
- http://johnnywey.wordpress.com/2012/05/20/jsonp-how-does-it-work/
PS:今天在和GR童鞋談論校長的 《淘寶技術這十年》 時候, 發現這么一個知識點:
生成首頁后,對Web前端稍微有點常識的人都應該知道,瀏覽器下一步會加載頁面中用到的CSS、JS(JavaScript)、圖片等樣式、腳本和資源文件。但是可能相對較少的人才會知道,你的瀏覽器在同一個域名下并發加載的資源數量是有限的,例如IE 6和IE 7是兩個,IE 8是6個,chrome各版本不大一樣,一般是4~6個。我剛剛看了一下,我訪問淘寶網首頁需要加載126個資源,那么如此小的并發連接數自然會加載很久。
好了,就到這里了。
THE END