跨域是指從一個域名的網(wǎng)頁去請求另一個域名的資源。比如從www.baidu.com 頁面去請求 www.google.com 的資源??缬虻膰栏褚稽c的定義是:只要 協(xié)議,域名,端口有任何一個的不同,就被當作是跨域
原因就是安全問題:如果一個網(wǎng)頁可以隨意地訪問另外一個網(wǎng)站的資源,那么就有可能在客戶完全不知情的情況下出現(xiàn)安全問題。比如下面的操作就有安全問題:
既然有安全問題,那為什么又要跨域呢? 有時公司內(nèi)部有多個不同的子域,比如一個是location.company.com ,而應用是放在app.company.com , 這時想從 app.company.com去訪問 location.company.com 的資源就屬于跨域。
由于瀏覽器一般不對script,img等進行跨域限制,所以我們有機會通過script的方式來實現(xiàn)跨域訪問。
跨域訪問需要用到兩樣東東,一個是JSON,一種基于文本的傳輸協(xié)議;一種是JSONP,一群碼農(nóng)想出來的跨域解決方案。關(guān)于JSON與JSONP的解釋,可以參考 JSON & JSONP
服務端要檢查訪問的請求參數(shù),如果沒有callback,則可以按照之前的流程走;如果帶著callback參數(shù),則需要將返回的結(jié)果包裝在callback里面。
比如請求的URL是: app.company.com/location?callback=myCallback , 那么服務端則需要把結(jié)果封裝進myCallback 函數(shù)里面, 如下
if (params.query && params.query.callback) { //console.log(params.query.callback); var str = params.query.callback '(' JSON.stringify(data) ')';//jsonp res.end(str); } else { res.end(JSON.stringify(data));//普通的json }
客戶端有多種方式可以實現(xiàn)JSONP的調(diào)用:
$scope.jqueryJsonpRequest = function(){ jQuery.ajax({ type: 'get', async: false, url: 'https://public-api.wordpress.com/rest/v1/sites/wtmpeachtest.wordpress.com/posts', dataType: 'jsonp', jsonp: 'callback',//傳遞給請求處理程序或頁面的,用以獲得jsonp回調(diào)函數(shù)名的參數(shù)名(一般默認為:callback) jsonpCallback:'flightHandler',//自定義的jsonp回調(diào)函數(shù)名稱,默認為jQuery自動生成的隨機函數(shù)名,也可以寫'?',jQuery會自動為你處理數(shù)據(jù) success: function(json){ alert('success' JSON.stringify(json)); }, error: function(){ alert('fail'); } }); };
$http.jsonp('https://public-api.wordpress.com/rest/v1/sites/wtmpeachtest.wordpress.com/posts?callback=JSON_CALLBACK') .success(function(data){ alert('success:' data); }).error(function(err){ alert('error:' err); });
手動實現(xiàn)
不管是jQuery也好,AngularJS也罷,底下都不是發(fā)起XHR (XML HTTP Request),而都是通過加載javascript的方式來做的,所以如果項目沒有依賴jQuery或者AngularJS,則可以自己手動實現(xiàn)jsonp的調(diào)用。
原理很簡單,就是用javascript動態(tài)加載一個script文件,同時定義一個callback函數(shù)給script執(zhí)行而已。
//定義callback 函數(shù)var myCallbackFunction = function(data){ // 對返回的數(shù)據(jù)做后續(xù)處理 alert('uuu:' JSON.stringify(data)); }//把callback函數(shù)賦給window對象,供script回調(diào) window.myCallbackFunction = myCallbackFunction;//創(chuàng)建并加載scriptvar script = document.createElement('script');script.src = 'https://public-api.wordpress.com/rest/v1/sites/wtmpeachtest.wordpress.com/posts?callback=myCallbackFunction';document.body.appendChild(script);