jsonp
原理:
JSONP 利用 <script>元素的這個開放策略,網頁可以得到從其他來源動態產生的JSON數據,而這種使用模式就是所謂的 JSONP。用JSONP抓到的數據并不是JSON,而是任意的JavaScript,用 JavaScript解釋器運行而不是用JSON解析器解析。
<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>
遠程的remote.js
localHandler({"result":"我是遠程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>
請求flightResult.aspx獲取的數據
flightHandler({
"code": "CA1998",
"price": 1780,
"tickets": 5
});
調用的url中傳遞了一個code參數,告訴服務器我要查的是CA1998次航班的信息,而callback參數則告訴服務器,我的本地回調函數叫做flightHandler,所以請把查詢結果傳入這個函數中進行調用。
劣勢: 支持get 安全性不高 (可以通過動態生成jsonp解決)
與ajax的區別:
但ajax和jsonp其實本質上是不同的東西。ajax的核心是通過XmlHttpRequest獲取非本頁內容,而jsonp的核心則是動態添加<script>標簽來調用服務器提供的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'
這種形式方便歸方便,但也有其方便帶來的隱患
安全性,當一個站點被攻擊后,另一個站點會引起安全漏洞。
若頁面中引入多個iframe,要想操作所有iframe,domain需要全部設置成一樣的。
HTML5中的postMessage
postMessage隸屬于html5,但是它支持IE8+和其他瀏覽器,可以實現同域傳遞,也能實現跨域傳遞。它包括發送消息postMessage和接收消息message功能。
postMessage調用語法如下
otherWindow.postMessage(message, targetOrigin, [transfer]);
- otherWindow : 其他窗口的一個引用,比如iframe的contentWindow屬性、執行window.open返回的窗口對象、或者是命名過或數值索引的window.frames。
- message : 將要發送到其他 window的數據,類型為string或者object。
- targetOrigin : 通過窗口的origin屬性來指定哪些窗口能接收到消息事件,其值可以是字符串"*"(表示無限制)或者一個URI。
- transfer (可選) : 一串和message 同時傳遞的 Transferable 對象。
接收消息message 的屬性有:
- data :從其他 window 中傳遞過來的數據。
- origin :調用 postMessage 時消息發送方窗口的 origin 。
- source :對發送消息的窗口對象的引用。
示例如下:域名http://127.0.0.1:9000頁面A通過iframe嵌入了http://127.0.0.1頁面B,接下來頁面A將通過postMessage對頁面B進行數據傳遞,頁面B將通過message屬性接收頁面A的數據
頁面A發送消息代碼
<!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發送消息', 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對象
if(origin === "http://127.0.0.1:9000"){
console.log(data, origin, source);
}
};
// 事件兼容簡單處理
if (window.addEventListener) {
window.addEventListener('message', onmessage, false);
}
else if (window.attachEvent) {
window.attachEvent('onmessage', onmessage);
}
else {
window.onmessage = onmessage;
}
</script>
運行結果如下