詳解JSONP,JSONP不再神祕
首先要知道JSONP是幹什麼的?很簡單,就是解決跨域問題的(什麼叫做跨域?自行百度)
1.就是說,我們在使用AJAX去訪問一個存在跨域的檔案時,不管是什麼樣的請求,不管是什麼樣的頁面,我們都不會獲取成功
2.但是,如果我們在前端經歷的起起落落的人都會發現,頁面上我們去載入外部JS檔案時候從來都不會出現因為跨域的問題而載入失敗,還有就是<img>標籤,不管我們從哪裡載入圖片,都不會因為跨域問題而載入失敗,當然還有<iframe>標籤,總結如下:帶src標籤的屬性都不受跨域的影響
3.於是如果們向跨域去訪問某個資料時,我們可以將資料寫在一個JS檔案當中,然後載入這個JS檔案就可以訪問到
4.上邊已經說了資料可以放在JS檔案中,伺服器端就是動態的生成JSON檔案,目的就是把客戶端需要的資料裝進去
5.客戶端在對JSON檔案調取成功後,獲取到自己需要的資料,然後按照自己的需求進行處理就可以,這種載入資料的方式像AJAX,但是其實是不一樣的
6.為了便於客戶端使用資料,逐漸形成一種非正式傳輸協議,人們叫它JSONP,這個協議的一個最重要的點在於,允許使用者傳遞callback引數給伺服器,伺服器返回資料時會將callback引數作為函式名來包裹住JSON資料,這樣客戶端就可以隨意的定製自己的函式來自動處理資料了
JSONP的客戶端具體實現:
1.我們知道哪怕是跨域JS的檔案,我們都可以使用<script>標籤來載入
我們在遠端伺服器下建立一個app.js檔案,程式碼如下:
alert('我是遠端檔案');
我們在本地的HTML檔案中呼叫這個JS檔案:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <script type="text/javascript" src="http://remoteserver.com/remote.js"></script> </head> <body> </body> </html>
沒有任何的疑問,執行這個html檔案,頁面會彈出來一個提示框(執行外部JS檔案成功)
2.現在我們在這個html中定義一個函式,然後我們在遠端的app.js檔案中傳入資料進行呼叫
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <script type="text/javascript"> var localHandler = function(data){ alert('我是本地函式,可以被跨域的remote.js檔案呼叫,遠端js帶來的資料是:' + data.result); }; </script> <script type="text/javascript" src="http://remoteserver.com/remote.js"></script> </head> <body> </body> </html>
spp.js檔案的程式碼如下:
localHandler({"result":"我是遠端js帶來的資料"});
執行HTML檔案,我們發現,頁面出現提示框,資料呼叫成功
但是問題來了,我們如何讓遠端的伺服器指導我們要呼叫的函式名稱是什麼呢?
3.聰明的人肯定會想到,就是伺服器端動態的生成JS指令碼就行了,這樣,我們在呼叫的時候直接傳過去函式名,並且告訴伺服器你需要什麼的資料,然後伺服器按照需求返回就行了:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <script type="text/javascript"> // 得到航班資訊查詢結果後的回撥函式 var flightHandler = function(data){ alert('你查詢的航班結果是:票價 ' + data.price + ' 元,' + '餘票 ' + data.tickets + ' 張。'); }; // 提供jsonp服務的url地址(不管是什麼型別的地址,最終生成的返回值都是一段javascript程式碼) var url = "http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998&callback=flightHandler"; // 建立script標籤,設定其屬性 var script = document.createElement('script'); script.setAttribute('src', url); // 把script標籤加入head,此時呼叫開始 document.getElementsByTagName('head')[0].appendChild(script); </script> </head> <body> </body> </html>
這次的程式碼變化比較大,不再直接把遠端js檔案寫死,而是編碼實現動態查詢,而這也正是jsonp客戶端實現的核心部分,本例中的重點也就在於如何完成jsonp呼叫的全過程。
我們看到呼叫的url中傳遞了一個code引數,告訴伺服器我要查的是CA1998次航班的資訊,而callback引數則告訴伺服器,我的本地回撥函式叫做flightHandler,所以請把查詢結果傳入這個函式中進行呼叫。
OK,伺服器很聰明,這個叫做flightResult.aspx的頁面生成了一段這樣的程式碼提供給html
flightHandler({ "code": "CA1998", "price": 1780, "tickets": 5 });
4.現在已經對原理有了足夠的瞭解,那麼我們現在就可以封裝程式碼,方便以後的使用:
(JQuery實現JSONP)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head> <title>Untitled Page</title> <script type="text/javascript" src=jquery.min.js"></script> <script type="text/javascript"> jQuery(document).ready(function(){ $.ajax({ type: "get", async: false, url: "http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998", dataType: "jsonp", jsonp: "callback",//傳遞給請求處理程式或頁面的,用以獲得jsonp回撥函式名的引數名(一般預設為:callback) jsonpCallback:"flightHandler",//自定義的jsonp回撥函式名稱,預設為jQuery自動生成的隨機函式名,也可以寫"?",jQuery會自動為你處理資料 success: function(json){ alert('您查詢到航班資訊:票價: ' + json.price + ' 元,餘票: ' + json.tickets + ' 張。'); }, error: function(){ alert('fail'); } }); }); </script> </head> <body> </body> </html>
是不是有點奇怪?為什麼我這次沒有寫flightHandler這個函式呢?而且竟然也執行成功了!
這就是jQuery的功勞了,jquery在處理jsonp型別的ajax時(,雖然jquery也把jsonp歸入了ajax,但其實它們真的不是一回事兒),自動幫你生成回撥函式並把資料取出來供success屬性方法來呼叫,是不是很爽呀?
補充
這裡針對ajax與jsonp的異同再做一些補充說明:
1、ajax和jsonp這兩種技術在呼叫方式上”看起來”很像,目的也一樣,都是請求一個url,然後把伺服器返回的資料進行處理,因此jquery和ext等框架都把jsonp作為ajax的一種形式進行了封裝。
2、但ajax和jsonp其實本質上是不同的東西。ajax的核心是通過XmlHttpRequest獲取非本頁內容,而jsonp的核心則是動態新增