跨域是指從一個域名的網頁去請求另外一個域名的資源。好比從www.baidu.com 頁面去請求 www.google.com 的資源。可是通常狀況javascript
下不能這麼作,它是由瀏覽器的同源策略形成的,是瀏覽器對JavaScript施加的安全限制。跨域的嚴格一點的定義是:只要 協議,域名,端口php
有任何一個的不一樣,就被看成是跨域。html
所謂同源是指,域名,協議,端口均相同。這裏說的js跨域是指經過js在不一樣的域之間進行數據傳輸或通訊,好比用ajax向一個不一樣的域請求數據,java
或者經過js獲取頁面中不一樣域的框架中(iframe)的數據。jquery
總結:只要協議、域名、端口有任何一個不一樣,都被看成是不一樣的域。web
詳細解釋請看下圖:ajax
假設如今有a.com和b.com兩個域,若是沒有這一安全策略,那麼當用戶在訪問a.com時,a.com的一段腳本就能夠在不加載b.com的頁面而隨意json
修改或者獲取b.com上面的內容。這樣將會致使b.com頁面的頁面發生混亂,甚至信息被獲取,包括服務器端發來的session。這樣的話,咱們的跨域
web世界將是一片混亂。也是由於瀏覽器的同源策略,保證來至不一樣源的對象不會互相干擾,保證了咱們訪問頁面最基本的安全。瀏覽器
既然有安全問題,那爲何又要跨域呢? 有時公司內部有多個不一樣的子域,好比一個是location.company.com ,而應用是放在app.company
.com ,這時想從 app.company.com去訪問 location.company.com 的資源就屬於跨域。
CORS(Cross-Origin Resource Sharing
)跨域資源共享,定義了必須在訪問跨域資源時,瀏覽器與服務器應該如何溝通。CORS
背後的基本思想
就是使用自定義的HTTP頭部讓瀏覽器與服務器進行溝通,從而決定請求或響應是應該成功仍是失敗。
服務器端對於CORS
的支持,主要就是經過設置Access-Control-Allow-Origin
來進行的。若是瀏覽器檢測到相應的設置,就能夠容許Ajax進行跨域
的訪問。
只須要在後臺中加上響應頭來容許域請求!在被請求的Response header中加入如下設置,就能夠實現跨域訪問了!
//指定容許其餘域名訪問
'Access-Control-Allow-Origin:*'//或指定域 //響應類型
'Access-Control-Allow-Methods:GET,POST'
//響應頭設置
'Access-Control-Allow-Headers:x-requested-with,content-type'
jsonp採用script標籤的src屬性實現跨域獲取資源。文檔中的全部帶「src」屬性的標籤均可以跨域加載資源,而不受同源策略的限制。
例如:在瀏覽器中<script>、<img>、<iframe>、<link>等標籤均可以跨域加載資源,而不受同源策略的限制。這些帶「src」屬性的標籤在
每次加載時,其實是由瀏覽器發起了一次GET請求。不一樣於XMLHttpRequest的是,經過src加載的資源,瀏覽器限制了Javascript的權限,
使其不能讀、寫返回內容。
XMLHttpRequest受到同源策略的約束,不能跨域訪問資源。但隨着跨域請求的需求愈來愈迫切,W3C標準制定了XMLHttpRequest跨域訪問
標準:它須要經過目標域返回的HTTP頭來受權是否容許跨域行爲。這一跨域方案的安全基礎是信任「Javascript沒法控制該HTTP頭」。
JSONP由兩部分組成:回調函數和數據。回調函數是當響應到來時應該在頁面中調用的函數,而數據就是傳入回調函數中的JSON數據。
JSONP的原理:經過script標籤引入一個js文件,這個js文件載入成功後會執行咱們在url參數中指定的函數,而且會把咱們須要的json數據
做爲參數傳入。因此jsonp是須要服務器端的頁面進行相應的配合的。(即用javascript動態加載一個script文件,同時定義一個callback
函數給script執行而已。)在js中,咱們直接用XMLHttpRequest
請求不一樣域上的數據時,是不能夠的。可是,在頁面上引入不一樣域上的js腳本
文件倒是能夠的,jsonp正是利用這個特性來實現的。 例如:有個a.html頁面,它裏面的代碼須要利用ajax獲取一個不一樣域上的json數據,
假設這個json數據地址是http://example.com/data.php,那麼a.html中的代碼就能夠這樣:
<script type="text/javascript">
function dosomething(jsondata){ //處理得到的json數據
} </script>
<script src="http://example.com/data.php?callback=dosomething"></script>
js文件載入成功後會執行咱們在url參數中指定的函數,而且會把咱們須要的json數據做爲參數傳入。因此jsonp是須要服務器端的頁面進行
相應的配合的。
<?php $callback = $_GET['callback'];//獲得回調函數名
$data = array('a','b','c');//要返回的數據
echo $callback.'('.json_encode($data).')';//輸出
?>
最終,輸出結果爲:dosomething(['a','b','c']);
若是你的頁面使用jquery,那麼經過它封裝的方法就能很方便的來進行jsonp操做了。
<script type="text/javascript"> $.getJSON('http://example.com/data.php?callback=?,function(jsondata)'){ //處理得到的json數據
}); </script>
jquery
會自動生成一個全局函數來替換callback=?
中的問號,以後獲取到數據後又會自動銷燬,實際上就是起一個臨時代理函數的做用。$.getJSON
方法會自動判斷是否跨域,不跨域的話,就調用普通的ajax
方法;跨域的話,則會以異步加載js文件的形式來調用jsonp
的回調函數。
JSONP的優勢是:它不像XMLHttpRequest
對象實現的Ajax請求那樣受到同源策略的限制;它的兼容性更好,在更加古老的瀏覽器中均可以運行,
不需要XMLHttpRequest或ActiveX的支持;而且在請求完畢後能夠經過調用callback的方式回傳結果。
JSONP的缺點則是:它只支持GET請求而不支持POST等其它類型的HTTP請求;它只支持跨域HTTP請求這種狀況,不能解決不一樣域的兩個頁面
之間如何進行JavaScript
調用的問題。
CORS與JSONP相比,無疑更爲先進、方便和可靠。
一、 JSONP只能實現GET請求,而CORS支持全部類型的HTTP請求。
二、 使用CORS,開發者可使用普通的XMLHttpRequest發起請求和得到數據,比起JSONP有更好的錯誤處理。
三、 JSONP主要被老的瀏覽器支持,它們每每不支持CORS,而絕大多數現代瀏覽器都已經支持了CORS)。
瀏覽器都有一個同源策略,其限制之一就是第一種方法中咱們說的不能經過ajax的方法去請求不一樣源中的文檔。 它的第二個限制是瀏覽器中不
同域的框架之間是不能進行js的交互操做的。
不一樣的框架之間是能夠獲取window對象的,但卻沒法獲取相應的屬性和方法。好比,有一個頁面,它的地址是http://www.example.com/a.html
,
在這個頁面裏面有一個iframe
,它的src是http://example.com/b.html
, 很顯然,這個頁面與它裏面的iframe
框架是不一樣域的,因此咱們是沒法
經過在頁面中書寫js代碼來獲取iframe
中的東西的:
<script type="text/javascript">
function test(){ var iframe = document.getElementById('ifame'); var win = document.contentWindow;//能夠獲取到iframe裏的window對象,但該window對象的屬性和方法幾乎是不可用的
var doc = win.document;//這裏獲取不到iframe裏的document對象
var name = win.name;//這裏一樣獲取不到window對象的name屬性
} </script>
<iframe id = "iframe" src="http://example.com/b.html" onload = "test()"></iframe>
這個時候,document.domain
就能夠派上用場了,咱們只要把http://www.example.com/a.html
和 http://example.com/b.html
這兩個頁面的
document.domain都設成相同的域名就能夠了。但要注意的是,document.domain的設置是有限制的,咱們只能把document.domain設置
成自身或更高一級的父域,且主域必須相同。例如:a.b.example.com 中某個文檔的document.domain 能夠設成a.b.example.com、
b.example.com 、example.com中的任意一個,可是不能夠設成 c.a.b.example.com,由於這是當前域的子域,也不能夠設成baidu.com,
由於主域已經不相同了。
1.在頁面 http://www.example.com/a.html
中設置document.domain
:
<iframe id = "iframe" src="http://example.com/b.html" onload = "test()"></iframe> <script type="text/javascript"> document.domain = 'example.com';//設置成主域 function test(){ alert(document.getElementById('iframe').contentWindow);//contentWindow 可取得子窗口的 window 對象 } </script>
2.在頁面 http://example.com/b.html
中也設置document.domain
:
<script type="text/javascript"> document.domain = 'example.com';//在iframe載入這個頁面也設置document.domain,使之與主頁面的document.domain相同 </script>
修改document.domain
的方法只適用於不一樣子域的框架間的交互。
web sockets是一種瀏覽器的API,它的目標是在一個單獨的持久鏈接上提供全雙工、雙向通訊。(同源策略對web sockets不適用)
web sockets原理:在js建立了web socket以後,會有一個HTTP請求發送到瀏覽器以發起鏈接。取得服務器響應後,創建的鏈接會使用HTTP升級
從HTTP協議交換爲web sockt協議。
只有在支持web socket協議的服務器上才能正常工做。
var socket = new WebSockt('ws://www.baidu.com');//http->ws; https->wss socket.send('hello WebSockt'); socket.onmessage = function(event){ var data = event.data; }
建議使用CORS解決跨域問題