同源策略:
什么是同源:只有在兩個頁面的協議(http://或者https://)、域名(www.baidu.com)、端口號(80端口,默認是80)都相同的情況下,這兩個頁面才是同源的。
同源策略限制的能力:非同源的兩個頁面,不能互相訪問對方設置的本機存儲數據、不能互相操作對方的DOM、ajax不能互相發送請求。
什么是跨域:在一臺服務器的頁面中,請求另一臺服務器的數據。這種行為就是跨域(兩個非同源服務器互相請求數據)。
AJAX規避同源策略(JSONP):
jsonp的本質:
1、利用標簽的src屬性可以加載任意服務器的接口內容的特性,把要請求的跨域服務器接口設置在該src屬性中,并憑借一個回調函數作為參數;
2、在服務器端收到請求后,取出傳進來的函數名,拼接成函數執行的形式,把前端需要的數據設置在函數參數中,一塊返還給前端;
3、前端在收到了服務器返回的函數執行碼時,開始觸發回調函數,在回調函數中就可以獲取到想要的數據了;
代碼如下:
// 1、創建script標簽
var scriptTag = document.createElement('script');
// 2、設置標簽類型
scriptTag.type = 'text/javascript';
// 3、設置請求的接口
scriptTag.src = 'http://10.0.153.197:8888/news?callback=getData';
// 4、拼接標簽進文檔流
window.onload = function() {
document.head.appendChild(scriptTag);
}
// 設置回調函數
function getData (data) {
console.log(data);
}
JSONP的客戶端具體實現:
1、我們知道,哪怕跨域js文件中的代碼(當然指符合web腳本安全策略的),web頁面也是可以無條件執行的。
遠程服務器remoteserver.com根目錄下有個remote.js文件代碼如下:
alert('我是遠程文件');
本地服務器localserver.com下有個jsonp.html頁面代碼如下:
<script type="text/javascript" src="http://remoteserver.com/remote.js">
毫無疑問,頁面將會彈出一個提示窗體,顯示跨域調用成功。
2、現在我們在jsonp.html頁面定義一個函數,然后在遠程remote.js中傳入數據進行調用。
remote.js文件代碼如下:
localHandler({"result":"我是遠程js帶來的數據"});
jsonp.html頁面代碼如下:
varlocalHandler=function(data){
alert('我是本地函數,可以被跨域的remote.js文件調用,遠程js帶來的數據是:'+data.result);
};
<script type="text/javascript" src="http://remoteserver.com/remote.js">
運行之后查看結果,頁面成功彈出提示窗口,顯示本地函數被跨域的遠程js調用成功,并且還接收到了遠程js帶來的數據。但是又一個問題出現了,我怎么讓遠程js知道它應該調用的本地函數叫什么名字呢?畢竟是jsonp的服務者都要面對很多服務對象,而這些服務對象各自的本地函數都不相同啊?我們接著往下看。
3、其實只要服務端提供的js腳本是動態生成的就行了,這樣調用者可以傳一個參數過去告訴服務端“我想要一段調用XXX函數的js代碼,請你返回給我”,于是服務器就可以按照客戶端的需求來生成js腳本并響應了。
看jsonp.html頁面的代碼:
//得到航班信息查詢結果后的回調函數varflightHandler=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);
這次的代碼變化比較大,不再直接把遠程js文件寫死,而是編碼實現動態查詢,而這也正是jsonp客戶端實現的核心部分,本例中的重點也就在于如何完成jsonp調用的全過程。
我們看到調用的url中傳遞了一個code參數,告訴服務器我要查的是CA1998次航班的信息,而callback參數則告訴服務器,我的本地回調函數叫做flightHandler,所以請把查詢結果傳入這個函數中進行調用。
OK,服務器很聰明,這個叫做flightResult.aspx的頁面生成了一段這樣的代碼提供給jsonp.html(服務端的實現這里就不演示了,與你選用的語言無關,說到底就是拼接字符串):
flightHandler({
"code": "CA1998",
"price": 1780,
"tickets": 5
});
我們看到,傳遞給flightHandler函數的是一個json,它描述了航班的基本信息。運行一下頁面,成功彈出提示窗口,jsonp的執行全過程順利完成!