跨域是指從一個域名的網頁去請求另外一個域名的資源。好比從www.baidu.com 頁面去請求 www.google.com 的資源。跨域的嚴格一點的定義是:只要 協議,域名,端口有任何一個的不一樣,就被看成是跨域javascript
緣由就是安全問題:若是一個網頁能夠隨意地訪問另一個網站的資源,那麼就有可能在客戶徹底不知情的狀況下出現安全問題。好比下面的操做就有安全問題:php
既然有安全問題,那爲何又要跨域呢? 有時公司內部有多個不一樣的子域,好比一個是location.company.com ,而應用是放在app.company.com , 這時想從 app.company.com去訪問 location.company.com 的資源就屬於跨域。html
因爲瀏覽器通常不對script,img等進行跨域限制,因此咱們有機會經過script的方式來實現跨域訪問。
html5
跨域訪問須要用到兩樣東東,一個是JSON,一種基於文本的傳輸協議;一種是JSONP,一羣碼農想出來的跨域解決方案。關於JSON與JSONP的解釋,能夠參考 JSON & JSONPjava
服務端要檢查訪問的請求參數,若是沒有callback,則能夠按照以前的流程走;若是帶着callback參數,則須要將返回的結果包裝在callback裏面。jquery
好比請求的URL是: app.company.com/location?callback=myCallback , 那麼服務端則須要把結果封裝進myCallback 函數裏面, 以下angularjs
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 }
客戶端有多種方式能夠實現JSONP的調用:ajax
$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回調函數名的參數名(通常默認爲:callback) jsonpCallback:"flightHandler",//自定義的jsonp回調函數名稱,默認爲jQuery自動生成的隨機函數名,也能夠寫"?",jQuery會自動爲你處理數據 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); });
不論是jQuery也好,AngularJS也罷,底下都不是發起XHR (XML HTTP Request),而都是經過加載JavaScript的方式來作的,因此若是項目沒有依賴jQuery或者AngularJS,則能夠本身手動實現jsonp的調用。json
原理很簡單,就是用javascript動態加載一個script文件,同時定義一個callback函數給script執行而已。api
//定義callback 函數 var myCallbackFunction = function(data){ // 對返回的數據作後續處理 alert('uuu:'+JSON.stringify(data)); } //把callback函數賦給window對象,供script回調 window.myCallbackFunction = myCallbackFunction; //建立並加載script var script = document.createElement('script'); script.src = 'https://public-api.wordpress.com/rest/v1/sites/wtmpeachtest.wordpress.com/posts?callback=myCallbackFunction'; document.body.appendChild(script);
jsonp的最基本的原理是:動態添加一個<script>標籤,而script標籤的src屬性是沒有跨域的限制的。這樣說來,這種跨域方式其實與ajax XmlHttpRequest協議無關了.
這樣其實"jQuery AJAX跨域問題"就成了個僞命題了,jquery $.ajax方法名有誤導人之嫌.
若是設爲dataType: 'jsonp', 這個$.ajax方法就和ajax XmlHttpRequest沒什麼關係了,取而代之的則是JSONP協議.
JSONP是一個非官方的協議,它容許在服務器端集成Script tags返回至客戶端,經過javascript callback的形式實現跨域訪問JSONP即JSON with Padding。因爲同源策略的限制,XmlHttpRequest只容許請求當前源(域名、協議、端口)的資源。若是要進行跨域請求,咱們能夠經過使用html的script標記來進行跨域請求,並在響應中返回要執行的script代碼,其中能夠直接使用JSON傳遞javascript對象。這種跨域的通信方式稱爲JSONP。
jsonCallback 函數jsonp1236827957501(....): 是瀏覽器客戶端註冊的,獲取跨域服務器上的json數據後,回調的函數
Jsonp原理:
首先在客戶端註冊一個callback (如:'jsoncallback'), 而後把callback的名字(如:jsonp1236827957501)傳給服務器。注意:服務端獲得callback的數值後,要用jsonp1236827957501(......)把將要輸出的json內容包括起來,此時,服務器生成 json 數據才能被客戶端正確接收。
而後以 javascript 語法的方式,生成一個function , function 名字就是傳遞上來的參數 'jsoncallback'的值 jsonp1236827957501 .
最後將 json 數據直接以入參的方式,放置到 function 中,這樣就生成了一段 js 語法的文檔,返回給客戶端。
客戶端瀏覽器,解析script標籤,並執行返回的 javascript 文檔,此時javascript文檔數據,做爲參數,
傳入到了客戶端預先定義好的 callback 函數(如上例中jquery $.ajax()方法封裝的的success: function (json))裏.(動態執行回調函數)
能夠說jsonp的方式原理上和<script src="http://跨域/...xx.js"></script>是一致的(qq空間就是大量採用這種方式來實現跨域數據交換的) .JSONP是一種腳本注入(Script Injection)行爲,因此也有必定的安全隱患.
原理的示例代碼:
//客戶端的 javascript 代碼
var script=document.createElement("script");
script.src="http://www.pl4cj.com:8888/5/6/action.php?param=123&callback="+fnName;
document.getElementsByTagName("head")[0].appendChild(script)
//服務器端的PHP代碼,必定要有callback來進行回調,在這裏加上括號,是讓它以語句塊的方式來進行解析
<?php
<SPAN style="COLOR: #ff00ff">echo $_GET["callback"]."(".json_encode($_GET).");";
</SPAN>
注意:jquey是不支持post方式跨域的.
爲何呢?
雖然採用post +動態生成iframe是能夠達到post跨域的目的,但這樣作是一個比較極端的方式,不建議採用.
也能夠說get方式的跨域是合法的,post方式從安全角度上,被認爲是不合法的, 萬不得已仍是不要劍走偏鋒..
client端跨域訪問的需求看來也引發w3c的注意了,看資料說html5 WebSocket標準支持跨域的數據交換,應該也是一個未來可選的跨域數據交換的解決方案