面試中常常會(huì)問(wèn)到如何使用jsonp跨域(jsonp跨域的原理是什么)燕偶,這篇文章就給大家介紹一下相關(guān)的知識(shí)指么,如有不對(duì)榴鼎,麻煩指出 ~
1. 首先我們比較一下json和jsonp
- JSON是一種基于文本的數(shù)據(jù)交換方式,或者叫做數(shù)據(jù)描述格式巫财;
- JSONP是一種非官方跨域數(shù)據(jù)交互協(xié)議;
2.為什么會(huì)出現(xiàn)jsonp
1)赫舒、一個(gè)眾所周知的問(wèn)題悍及,Ajax直接請(qǐng)求普通文件存在跨域無(wú)權(quán)限訪問(wèn)的問(wèn)題接癌,甭管你是靜態(tài)頁(yè)面、動(dòng)態(tài)網(wǎng)頁(yè)缨叫、web服務(wù)荔燎、WCF,只要是跨域請(qǐng)求湖雹,一律不準(zhǔn)。
2)鸽嫂、不過(guò)我們又發(fā)現(xiàn)征讲,Web頁(yè)面上調(diào)用js文件時(shí)則不受是否跨域的影響(不僅如此,我們還發(fā)現(xiàn)凡是擁有"src"這個(gè)屬性的標(biāo)簽都擁有跨域的能力癣籽,比如<script>、<img>筷狼、<iframe>)匠童。
3)、于是可以判斷俏险,當(dāng)前階段如果想通過(guò)純web端(ActiveX控件扬绪、服務(wù)端代理、屬于未來(lái)的HTML5之Websocket等方式不算)跨域訪問(wèn)數(shù)據(jù)就只有一種可能挤牛,那就是在遠(yuǎn)程服務(wù)器上設(shè)法把數(shù)據(jù)裝進(jìn)js格式的文件里,供客戶端調(diào)用和進(jìn)一步處理。
4)、恰巧我們已經(jīng)知道有一種叫做JSON的純字符數(shù)據(jù)格式可以簡(jiǎn)潔的描述復(fù)雜數(shù)據(jù)竣蹦,更妙的是JSON還被js原生支持,所以在客戶端幾乎可以隨心所欲的處理這種格式的數(shù)據(jù)长窄。
5)、這樣子解決方案就呼之欲出了挠日,web客戶端通過(guò)與調(diào)用腳本一模一樣的方式翰舌,來(lái)調(diào)用跨域服務(wù)器上動(dòng)態(tài)生成的js格式文件(一般以JSON為后綴),顯而易見(jiàn)懂算,服務(wù)器之所以要?jiǎng)討B(tài)生成JSON文件庇麦,目的就在于把客戶端需要的數(shù)據(jù)裝入進(jìn)去。
6)山橄、客戶端在對(duì)JSON文件調(diào)用成功之后,也就獲得了自己所需的數(shù)據(jù)航棱,剩下的就是按照自己需求進(jìn)行處理和展現(xiàn)了,這種獲取遠(yuǎn)程數(shù)據(jù)的方式看起來(lái)非常像AJAX入桂,但其實(shí)并不一樣。
7)抗愁、為了便于客戶端使用數(shù)據(jù)呵晚,逐漸形成了一種非正式傳輸協(xié)議,人們把它稱(chēng)作JSONP饵隙,該協(xié)議的一個(gè)要點(diǎn)就是允許用戶傳遞一個(gè)callback參數(shù)給服務(wù)端,然后服務(wù)端返回?cái)?shù)據(jù)時(shí)會(huì)將這個(gè)callback參數(shù)作為函數(shù)名來(lái)包裹住JSON數(shù)據(jù)芯急,這樣客戶端就可以隨意定制自己的函數(shù)來(lái)自動(dòng)處理返回?cái)?shù)據(jù)了。
3.jsonp實(shí)現(xiàn)例子
- 假設(shè)遠(yuǎn)程的服務(wù)器remoteServer.com上有一段js文件娶耍,內(nèi)容為:
alert("hello world");
我們本地localhost.com上有一個(gè)頁(yè)面,里面引入了上面的js文件榕酒,當(dāng)我們?cè)跒g覽器中打開(kāi)此頁(yè)面時(shí),會(huì)發(fā)現(xiàn)可以成功的彈出hello world紊婉,這就表示跨域調(diào)用成功了辑舷。
- 如何跨域遠(yuǎn)程獲取數(shù)據(jù)呢
本地localhost.com上有一個(gè)頁(yè)面localhost.html,頁(yè)面內(nèi)容為:
<html>
<head>
<title></title>
<script type="text/javascript">
var localHandler = function(data){
alert('我是本地函數(shù)何缓,可以被跨域的remote.js文件調(diào)用,遠(yuǎn)程js帶來(lái)的數(shù)據(jù)是:' + data.result);
};
</script>
<script type="text/javascript" src="http://remoteserver.com/remote.js"></script>
</head>
<body>
</body>
</html>
remoteserver.com上的remote.js文件內(nèi)容:
localHandler({"result":"hello world"});
我們?cè)跒g覽器中打開(kāi)此頁(yè)面localhost.html乔妈,發(fā)現(xiàn)彈出了
我是本地函數(shù)氓皱,可以被跨域的remote.js文件調(diào)用,遠(yuǎn)程js帶來(lái)的數(shù)據(jù)是:hello world
跨域遠(yuǎn)程獲取數(shù)據(jù)的目的基本實(shí)現(xiàn)了股淡,但是又一個(gè)問(wèn)題出現(xiàn)了,我怎么讓遠(yuǎn)程js知道它應(yīng)該調(diào)用的本地函數(shù)叫什么名字呢唯灵?畢竟是jsonp的服務(wù)者都要面對(duì)很多服務(wù)對(duì)象隙轻,而這些服務(wù)對(duì)象各自的本地函數(shù)都不相同啊敛瓷?
<br >
- 解決遠(yuǎn)程服務(wù)器不知道該調(diào)用什么函數(shù)的問(wèn)題
思路:只要服務(wù)端提供的js腳本是動(dòng)態(tài)生成的,這樣調(diào)用者可以傳一個(gè)參數(shù)過(guò)去告訴服務(wù)端 "我想要一段調(diào)用XXX函數(shù)的js代碼呐籽,請(qǐng)你返回給我",于是服務(wù)器就可以按照客戶端的需求來(lái)生成js腳本并響應(yīng)了庶橱。
再看 localhost.html
<html>
<head>
<title></title>
<script type="text/javascript">
// 得到航班信息查詢結(jié)果后的回調(diào)函數(shù)
var flightHandler = function(data){
alert('你查詢的航班結(jié)果是:票價(jià) ' + data.price + ' 元贪惹,' + '余票 ' + data.tickets + ' 張。');
};
// 提供jsonp服務(wù)的url地址(不管是什么類(lèi)型的地址,最終生成的返回值都是一段javascript代碼)
var url = "http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998&callback=flightHandler";
// 創(chuàng)建script標(biāo)簽垫释,設(shè)置其屬性
var script = document.createElement('script');
script.setAttribute('src', url);
// 把script標(biāo)簽加入head,此時(shí)調(diào)用開(kāi)始
document.getElementsByTagName('head')[0].appendChild(script);
</script>
<script type="text/javascript" src="http://remoteserver.com/remote.js"></script>
</head>
<body>
</body>
</html>
我們看到調(diào)用的url中傳遞了一個(gè)code參數(shù)棵譬,告訴服務(wù)器我要查的是CA1998次航班的信息,而callback參數(shù)則告訴服務(wù)器曼尊,我的本地回調(diào)函數(shù)叫做flightHandler脏嚷,所以請(qǐng)把查詢結(jié)果傳入這個(gè)函數(shù)中進(jìn)行調(diào)用。
flightResult.aspx中:
{
"code": "CA1998",
"price": 1780,
"tickets": 5
}
- 封裝代碼,jquery實(shí)現(xiàn)jsonp
<html>
<head>
<title>Untitled Page</title>
<script type="text/javascript" src=jquery.min.js"></script>
<script type="text/javascript">
// 得到航班信息查詢結(jié)果后的回調(diào)函數(shù)
var flightHandler = function(data){ alert('你查詢的航班結(jié)果是:票價(jià) ' + data.price + ' 元神郊,' + '余票 ' + data.tickets + ' 張趾唱。'); };
jQuery(document).ready(function(){
$.ajax({
type: "get",
async: false,
url: "http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998",
dataType: "jsonp",
jsonp: "callback",//傳遞給請(qǐng)求處理程序或頁(yè)面的,用以獲得jsonp回調(diào)函數(shù)名的參數(shù)名(一般默認(rèn)為:callback)
jsonpCallback:"flightHandler",//自定義的jsonp回調(diào)函數(shù)名稱(chēng)夕晓,默認(rèn)為jQuery自動(dòng)生成的隨機(jī)函數(shù)名悠咱,也可以寫(xiě)"?",jQuery會(huì)自動(dòng)為你處理數(shù)據(jù)
success: function(json){
alert('您查詢到航班信息:票價(jià): ' + json.price + ' 元析既,余票: ' + json.tickets + ' 張。');
},
error: function(){
alert('fail');
}
});
});
</script>
</head>
<body>
</body>
</html>
jquery幫你生成回調(diào)函數(shù)并把數(shù)據(jù)取出來(lái)供success屬性方法來(lái)調(diào)用逗宜。
附其他實(shí)現(xiàn)跨域的方法:
- document.domain+iframe的設(shè)置
- 動(dòng)態(tài)創(chuàng)建script
- 利用iframe和location.hash
- window.name實(shí)現(xiàn)的跨域數(shù)據(jù)傳輸
- 使用HTML5 postMessage
- 利用flash
詳細(xì)介紹,點(diǎn)擊這里
參考文章:說(shuō)說(shuō)JSON和JSONP擂仍,也許你會(huì)豁然開(kāi)朗熬甚,含jQuery用例