什麼是跨域?
簡單的來說,出於安全方面的考慮,頁面中的JavaScript無法訪問其他伺服器上的資料,即“同源策略”。而跨域就是通過某些手段來繞過同源策略限制,實現不同伺服器之間通訊的效果。
具體策略限制情況可看下錶:
URL |
說明 |
允許通訊 |
http://www.a.com/a.js http://www.a.com/b.js |
同一網域名稱下 |
允許 |
http://www.a.com/lab/a.js http://www.a.com/script/b.js |
同一網域名稱下不同檔案夾 |
允許 |
http://www.a.com:8000/a.js http://www.a.com/b.js |
同一網域名稱,不同連接埠 |
不允許 |
http://www.a.com/a.js https://www.a.com/b.js |
同一網域名稱,不同協議 |
不允許 |
http://www.a.com/a.js http://127.0.0.100/b.js |
網域名稱和網域名稱對應ip |
不允許 |
http://www.a.com/a.js http://script.a.com/b.js |
主域相同,子域不同 |
不允許 |
http://www.a.com/a.js http://a.com/b.js |
同一網域名稱,不同次層網域(同上) |
不允許 |
http://www.a.com/a.js http://www.b.com/b.js |
不同網域名稱 |
不允許 |
什麼是JSONP?
JSON(JavaScript Object Notation) 是一種輕量級的資料交換格式,而JSONP(JSON with Padding)則是JSON 的一種“使用模式”,通過這種模式可以實現資料的跨域擷取。
JSONP跨域的原理
在同源策略下,在某個伺服器下的頁面是無法擷取到該伺服器以外的資料的,但img、iframe、script等標籤是個例外,這些標籤可以通過src屬性請求到其他伺服器上的資料。利用script標籤的開放策略,我們可以實現跨域請求資料,當然,也需要服務端的配合。當我們正常地請求一個JSON資料的時候,服務端返回的是一串JSON類型的資料,而我們使用JSONP模式來請求資料的時候,服務端返回的是一段可執行檔JavaScript代碼。
跨域: js有一個同源限制,簡單說來源不一樣的話就無法相互間互動.那麼怎麼算來源不一樣呢, 舉個例子:瀏覽器訪問-->伺服器A--->得到頁面A---頁面A中的js指令碼只能訪問伺服器A的資源(相同網域名稱和連接埠,此外網域名稱與對應的ip也算不同源,要麼都網域名稱,要麼都ip).
以上就是js的跨域問題,但是這裡需要注意一點的是伺服器A是沒有跨域的問題的,這個只有js存在這個問題,也就是說: 頁面A中js-->伺服器A--->跨域資源,這個路徑是可以.只有 頁面A中的js--->跨域資源,這個路徑是不行的.
然後說一下解決方案中的jsonp,這個不是一種格式,而是一種解決方案.
jsonp的原理:js雖然有同源限制,但是引入js檔案的時候卻沒有這個限制,也就是說:
<script type="text/javascript" src="xxx/xxxx.js"></script>
其中src屬性引入js檔案的時候是沒有同源限制的,此時是可以引入域外資源的.jsonp的原理就在這裡,通過動態建立一個以上那行js引入語句,通過其src屬性訪問域外資源.而域外資原始伺服器只要返回一個能被解析為js語句的字串即可達到返回結果的目的,形如:
callback({"key":"value",...})
其中callback是需要事先約定的名字,綠字部分為要返回到json字串,然後拼接成以上那種形式直接返回即可.這樣頁面中的js從服務端接收到這個拼接的字串後,就會直接執行本地的名為callback的js方法,這也就是為何callback這個需要事先約定的原因,需要保證頁面側要存在這個js方法,這個方法傳入的參數就為伺服器側的傳回值.
ajax是支援jsonp的,所以以上那些麻煩事情都會替我們做,寫法如下:
$.ajax({ type: 'GET', url: "http://127.0.0.1:8080/xxx/xxx", async: false, dataType: "jsonp", jsonp: "callback", success: function(result){ ..... }, timeout:3000 });
紅字部分標識我們使用jsonp的方式調用,實際上此時這個已經不是傳統意義上的ajax的get請求了,它的真實實現方式就是我們上文中說的那樣.其中紅字部分的callback為我們要和伺服器端進行溝通的部分,這個請求發送到伺服器端,實際上這樣的:
http://127.0.0.1:8080/xxx/xxx?callback=jqueryxxxx
伺服器端需要通過callback來取值(類似用request.getParameter("callback")),也就是取後面的jqueryxxxx等自動產生的值,這個值實際上就是對應的我們發送請求的ajax方法中的success回調方法,伺服器端如果返回
頁面中會自動執行success方法,且將{"ret":"ok"}傳給success方法的參數result.
以上就是ajax通過jsonp的方式實現跨域訪問的過程.可以看出基本不用我們做什麼額外操作,全都封裝好了.
ps:在jQuery中如何通過JSONP來跨域擷取資料
第一種方法是在ajax函數中設定dataType為'jsonp':
$.ajax({ dataType: 'jsonp', url: 'http://www.a.com/user?id=123', success: function(data){ //處理data資料 }});
第二種方法是利用getJSON來實現,只要在地址中加上callback=?參數即可:
$.getJSON('http://www.a.com/user?id=123&callback=?', function(data){ //處理data資料});
也可以簡單地使用getScript方法:
//此時也可以在函數外定義foo方法function foo(data){ //處理data資料}$.getJSON('http://www.a.com/user?id=123&callback=foo');
JSONP的應用
JSONP在開放API中可以起到非常重要的作用,開放API是運用在開發人員自己的應用上,而許多應用往往是在開發人員的伺服器上而不是在新浪微博的伺服器上,因此跨域請求資料成為開發人員們所需要解決的一大問題,廣大開放平台應該實現對JSONP的支援,這一點新浪微博開放平台便做的非常好(雖然某些API裡沒有說明,但實際上是可以使用JSONP方式調用的)。