jsonp
原理:
JSONP 利用 <script>元素的這個(gè)開放策略,網(wǎng)頁可以得到從其他來源動(dòng)態(tài)產(chǎn)生的JSON數(shù)據(jù)片任,而這種使用模式就是所謂的 JSONP森爽。用JSONP抓到的數(shù)據(jù)并不是JSON,而是任意的JavaScript,用 JavaScript解釋器運(yùn)行而不是用JSON解析器解析鹿榜。
<script type="text/javascript">
var localHandler = function(data){
alert('我是本地函數(shù),可以被跨域的remote.js文件調(diào)用锦爵,遠(yuǎn)程js帶來的數(shù)據(jù)是:' + data.result); };
</script>
<script type="text/javascript" src="http://remoteserver.com/remote.js"></script>
遠(yuǎn)程的remote.js
localHandler({"result":"我是遠(yuǎn)程js帶來的數(shù)據(jù)"});
我本地請(qǐng)求
<!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">
// 得到航班信息查詢結(jié)果后的回調(diào)函數(shù)
var flightHandler = function(data){
alert('你查詢的航班結(jié)果是:票價(jià) ' + data.price + ' 元舱殿,' + '余票 ' + data.tickets + ' 張。');
};
// 提供jsonp服務(wù)的url地址(不管是什么類型的地址险掀,最終生成的返回值都是一段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)用開始
document.getElementsByTagName('head')[0].appendChild(script);
</script>
</head>
<body>
</body>
</html>
請(qǐng)求flightResult.aspx獲取的數(shù)據(jù)
flightHandler({
"code": "CA1998",
"price": 1780,
"tickets": 5
});
調(diào)用的url中傳遞了一個(gè)code參數(shù)樟氢,告訴服務(wù)器我要查的是CA1998次航班的信息冈绊,而callback參數(shù)則告訴服務(wù)器,我的本地回調(diào)函數(shù)叫做flightHandler埠啃,所以請(qǐng)把查詢結(jié)果傳入這個(gè)函數(shù)中進(jìn)行調(diào)用死宣。
劣勢(shì): 支持get 安全性不高 (可以通過動(dòng)態(tài)生成jsonp解決)
與ajax的區(qū)別:
但ajax和jsonp其實(shí)本質(zhì)上是不同的東西。ajax的核心是通過XmlHttpRequest獲取非本頁內(nèi)容碴开,而jsonp的核心則是動(dòng)態(tài)添加<script>標(biāo)簽來調(diào)用服務(wù)器提供的js腳本毅该。
cors
document.domain+iframe(適用于主域名相同的情況)
在域名為http://server.example.com中的a.html
document.domain = 'example.com';
var $iframe = document.createElement('iframe');
$iframe.src = 'server.child.example.com/b.html';
$iframe.style.display = 'none';
document.body.appendChild($iframe);
$iframe.onload = function(){
var doc = $iframe.contentDocument || $iframe.contentWindow.document;
//在這里操作doc,也就是操作b.html
$iframe.onload = null;
};
在域名為http://server.child.example.com中的b.html
document.domain = 'example.com'
這種形式方便歸方便叹螟,但也有其方便帶來的隱患
安全性鹃骂,當(dāng)一個(gè)站點(diǎn)被攻擊后,另一個(gè)站點(diǎn)會(huì)引起安全漏洞罢绽。
若頁面中引入多個(gè)iframe,要想操作所有iframe静盅,domain需要全部設(shè)置成一樣的良价。
HTML5中的postMessage
postMessage隸屬于html5寝殴,但是它支持IE8+和其他瀏覽器,可以實(shí)現(xiàn)同域傳遞明垢,也能實(shí)現(xiàn)跨域傳遞蚣常。它包括發(fā)送消息postMessage和接收消息message功能。
postMessage調(diào)用語法如下
otherWindow.postMessage(message, targetOrigin, [transfer]);
- otherWindow : 其他窗口的一個(gè)引用痊银,比如iframe的contentWindow屬性抵蚊、執(zhí)行window.open返回的窗口對(duì)象、或者是命名過或數(shù)值索引的window.frames溯革。
- message : 將要發(fā)送到其他 window的數(shù)據(jù)贞绳,類型為string或者object。
- targetOrigin : 通過窗口的origin屬性來指定哪些窗口能接收到消息事件致稀,其值可以是字符串"*"(表示無限制)或者一個(gè)URI冈闭。
- transfer (可選) : 一串和message 同時(shí)傳遞的 Transferable 對(duì)象。
接收消息message 的屬性有:
- data :從其他 window 中傳遞過來的數(shù)據(jù)抖单。
- origin :調(diào)用 postMessage 時(shí)消息發(fā)送方窗口的 origin 萎攒。
- source :對(duì)發(fā)送消息的窗口對(duì)象的引用。
示例如下:域名http://127.0.0.1:9000頁面A通過iframe嵌入了http://127.0.0.1頁面B矛绘,接下來頁面A將通過postMessage對(duì)頁面B進(jìn)行數(shù)據(jù)傳遞耍休,頁面B將通過message屬性接收頁面A的數(shù)據(jù)
頁面A發(fā)送消息代碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>頁面A</title>
</head>
<body>
<h1>hello jsonp</h1>
<iframe src="http://127.0.0.1/b.html" id="iframe"></iframe>
</body>
</html>
<script>
window.onload = function() {
var $iframe = document.getElementById('iframe');
var targetOrigin = "http://127.0.0.1";
$iframe.contentWindow.postMessage('postMessage發(fā)送消息', targetOrigin);
};
</script>
頁面B接收消息代碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>頁面B</title>
</head>
<body>
<h1>hello jsonp</h1>
</body>
</html>
<script>
var onmessage = function (event) {
var data = event.data; //消息
var origin = event.origin; //消息來源地址
var source = event.source; //源Window對(duì)象
if(origin === "http://127.0.0.1:9000"){
console.log(data, origin, source);
}
};
// 事件兼容簡(jiǎn)單處理
if (window.addEventListener) {
window.addEventListener('message', onmessage, false);
}
else if (window.attachEvent) {
window.attachEvent('onmessage', onmessage);
}
else {
window.onmessage = onmessage;
}
</script>
運(yùn)行結(jié)果如下