Js中的跨域問題

1、什麼是跨域?

1.定義:

跨域是指從一個域名的網頁去請求另外一個域名的資源。好比從www.baidu.com 頁面去請求 www.google.com 的資源。可是通常狀況javascript

下不能這麼作,它是由瀏覽器的同源策略形成的,是瀏覽器對JavaScript施加的安全限制。跨域的嚴格一點的定義是:只要 協議,域名,端口php

有任何一個的不一樣,就被看成是跨域。html

所謂同源是指,域名,協議,端口均相同。這裏說的js跨域是指經過js在不一樣的域之間進行數據傳輸或通訊,好比用ajax向一個不一樣的域請求數據,java

或者經過js獲取頁面中不一樣域的框架中(iframe)的數據。jquery

總結:只要協議、域名、端口有任何一個不一樣,都被看成是不一樣的域。web

詳細解釋請看下圖:ajax

2、爲何瀏覽器要限制跨域訪問

假設如今有a.com和b.com兩個域,若是沒有這一安全策略,那麼當用戶在訪問a.com時,a.com的一段腳本就能夠在不加載b.com的頁面而隨意json

修改或者獲取b.com上面的內容。這樣將會致使b.com頁面的頁面發生混亂,甚至信息被獲取,包括服務器端發來的session。這樣的話,咱們的跨域

web世界將是一片混亂。也是由於瀏覽器的同源策略,保證來至不一樣源的對象不會互相干擾,保證了咱們訪問頁面最基本的安全。瀏覽器

3、爲何要跨域?

既然有安全問題,那爲何又要跨域呢? 有時公司內部有多個不一樣的子域,好比一個是location.company.com ,而應用是放在app.company

.com ,這時想從 app.company.com去訪問 location.company.com 的資源就屬於跨域。

4、解決跨域問題的方法

(1)跨域資源共享(CORS)

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'

(2)經過jsonp跨域

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的優缺點

JSONP的優勢是:它不像XMLHttpRequest對象實現的Ajax請求那樣受到同源策略的限制;它的兼容性更好,在更加古老的瀏覽器中均可以運行,

不需要XMLHttpRequest或ActiveX的支持;而且在請求完畢後能夠經過調用callback的方式回傳結果。

JSONP的缺點則是:它只支持GET請求而不支持POST等其它類型的HTTP請求;它只支持跨域HTTP請求這種狀況,不能解決不一樣域的兩個頁面

之間如何進行JavaScript調用的問題。

CORS和JSONP對比

CORS與JSONP相比,無疑更爲先進、方便和可靠。

一、 JSONP只能實現GET請求,而CORS支持全部類型的HTTP請求。

二、 使用CORS,開發者可使用普通的XMLHttpRequest發起請求和得到數據,比起JSONP有更好的錯誤處理。

三、 JSONP主要被老的瀏覽器支持,它們每每不支持CORS,而絕大多數現代瀏覽器都已經支持了CORS)。

(3)經過修改document.domain來跨子域

瀏覽器都有一個同源策略,其限制之一就是第一種方法中咱們說的不能經過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的方法只適用於不一樣子域的框架間的交互

(4)web sockets

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解決跨域問題

相關文章
相關標籤/搜索