跨域方法整理

    在講跨域前必須瞭解同源策略:同源策略,它是由Netscape提出的一個著名的安全策略。如今全部支持JavaScript 的瀏覽器都會使用這個策略。所謂同源是指,域名,協議,端口相同。當一個瀏覽器的兩個tab頁中分別打開來 百度和谷歌的頁面當一個百度瀏覽器執行一個腳本的時候會檢查這個腳本是屬於哪一個頁面的,即檢查是否同源,只有和百度同源的腳本纔會被執行。簡單的一句話就是:「若是兩個頁面擁有相同的協議(protocol),端口(若是指定),和主機,那麼這兩個頁面就屬於同一個源(origin)。」下圖爲是否同源:javascript

  

爲了保證用戶信息的安全,防止惡意的網站竊取數據。同源策略下:Cookie、LocalStorage 和 IndexDB 沒法讀取,DOM 沒法得到,AJAX 請求不能發送。(ps:若是想更多瞭解同源策略能夠看阮一峯大神的博客:http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html)。php

  爲了解決不一樣源之間通信,跨域所以而生:html

    方法一:JSONPhtml5

                 jsonp:JSONP是json with padding的簡稱,jsonp看起來跟json差很少,只不過是包含在函數中的json數據而已。java

callback({"name":"xiaotutu"});

 

 

 

由於script標籤是不受同源策略影響的,它能夠引入來自任何地方的js文件。而jsonp的原理就是,在客戶端和服務端定義一個函數,當客戶端發起一個請求時,服務端返回一段javascript代碼,其中調用了在客戶端定義的函數,並將相應的數據做爲參數傳入該函數。通常狀況下,爲了這個script標籤可以動態的調用,咱們能夠經過javascript動態的建立script標籤,這樣咱們就能夠靈活調用遠程服務了。代碼以下:web

        

function jsonp_callback(data) {
    console.log(data);
}
function jsonpAjax(){
    var url = "http://a.com/b.php?jsonp_callback=jsonp_callback";
    var script = document.createElement('script');
    // 發送請求
    script.src = url;
    document.head.appendChild(script);
}
jsonpAjax()

 

當服務器接受到callback時候會返回相應的代碼json

 

 

jsonp_callback({
   "name": "chentutu"
});

 

jsonp是想對來講比較簡單的,靈活的利用了<script>的不受限制從其它域加載資源。由於javascript是有效代碼因此在請求完成後,就會被當即執行。跨域

方法二:<img>瀏覽器

跟script同樣能不受其它域限制加載資源,使用它們的onload和onerror事件處理程序來肯定是否響應。但它只能用來發送GET請求,且沒法獲取服務端的響應文本,因此只能利用它實現一些簡單的、單向的跨域通訊,例如跟蹤用戶的點擊。你們看看下面的例子:安全

var img = new Image();
img.onload = function(){
    console.log('done')
    img.onload = null;
    img = null;
}
img.src = "http://xx/xx.gif"

方法三:CORS

   CORS(Cross-Origin Resource Sharing,跨源資源共享)是W3C小組制定的一個標準,它容許瀏覽器實現跨域通訊。經過創建一個XmlHttpRequest對象,CORS容許開發者象實現同源請求那樣實現跨源請求。CORS(跨源資源共享)的實現目標很是簡單。假設站點B想訪問站點A中的某些數據,使用同源請求將不能知足這一需求。可是,經過CORS請求,站點A能夠經過在部分頁面中加入特殊的響應頭的方法來容許站點B訪問。

    注意CORS只支持如下瀏覽器:

  • Chrome 3以上版本的瀏覽器
  • Firefox 3.5以上版本的瀏覽器
  • Safari 4以上版本的瀏覽器
  • Internet Explorer 8以上版本的瀏覽器

下面就是一個建立請求對象的代碼:

 function createCORSRequest(method, url) {
    var xhr = new XMLHttpRequest();
    if ("withCredentials" in xhr) {
        //檢查XMLHttpRequest對象是否擁有一個withCredentials屬性
        //withCredentials屬性只屬於XMLHTTPRequest2對象
        xhr.open(method, url, true);
    } 
    else if (typeof XDomainRequest != "undefined") {
        //不然,檢查XDomainRequest對象 Otherwise, check if XDomainRequest.
        //XDomainRequest對象只存在於IE瀏覽器中,且被IE瀏覽器用來建立CORS請求
        xhr = new XDomainRequest();
        xhr.open(method, url);

    } 
    else {
        //不然,CORS不被當前瀏覽器支持
        xhr = null;
    }
    return xhr;
}

var xhr = createCORSRequest('GET', url);
if (!xhr) {
    throw new Error('CORS不被支持!');
}

在默認狀況下,標準的CORS請求不發送或設置任何cookie。爲了在請求中包含cookie,你須要將XmlHttpRequest對象的withCredentials屬性值設爲true。爲了達到目的,服務器端必須將Access-Control-Allow-Credentials響應頭設爲true。.withCredentials屬性值的設置將會使跨源請求中能夠包含任何cookie,開發者也能夠經過使用該屬性值來跨源設置任何cookie。請注意,這些cookie也可使用同源安全策略,即被跨源設置的cookie中的內容不能被同源的JavaScript腳本代碼所訪問,只能被設置這些cookie的源所訪問。

一個使用CORS請求的完整代碼示例以下所示:

//建立XHR對象
function createCORSRequest(method, url) {
    var xhr = new XMLHttpRequest();
    if ("withCredentials" in xhr) {
        //Chrome/Safari/Firefox瀏覽器中的XHR對象
        xhr.open(method, url, true);
    } 
    else if (typeof XDomainRequest != "undefined") {
        //在IE瀏覽器中建立XDomainRequest對象
        xhr = new XDomainRequest();
        xhr.open(method, url);
    } 
    else {
        //CORS不被支持.
        xhr = null;
    }
    return xhr;
}
//從服務器端響應中獲取title標籤
function getTitle(text) {
    return text.match('')[1];
}
//建立CORS請求
function makeCorsRequest() {
    // bibliographica.org支持CORS請求
    var url = 'http://bibliographica.org/';

    var xhr = createCORSRequest('GET', url);
    if (!xhr) {
        alert('您的瀏覽器不支持跨源請求');
        return;
    }

    //處理服務器端響應
    xhr.onload = function() {
        var text = xhr.responseText;
        var title = getTitle(text);
        alert('來自' + url + '的響應: ' + title);
    };

    xhr.onerror = function() {
        alert('跨源請求失敗!');
    };
    xhr.send();
}

CORS分爲簡單和非簡單模式:詳細請見阮一峯大神的博客:http://www.ruanyifeng.com/blog/2016/04/cors.html

        方法四:document.domain

  • 原理:相同主域名不一樣子域名下的頁面,能夠設置document.domain讓它們同域
  • 限制:同域document提供的是頁面間的互操做,須要載入iframe頁面

如下是document.domain實際操做的代碼:

var ifr = document.createElement('iframe');
ifr.src = 'http://b.a.com/bar'; 
ifr.onload = function(){
    var ifrdoc = ifr.contentDocument || ifr.contentWindow.document;
    ifrdoc.getElementsById("foo").innerHTML);
};

ifr.style.display = 'none';
document.body.appendChild(ifr);

注意:若是修改了document.domain,則在某些機器上的IE678裏,獲取location.href有權限異常。document.domain只能從子域設置到主域,往下設置以及往其餘域名設置都是不容許的。

方法五:window.postMessage

 

  • 原理:HTML5容許窗口之間發送消息
  • 限制:瀏覽器須要支持HTML5,獲取窗口句柄後才能相互通訊
//發送端
var win = window.open('http://b.com/bar');
win.postMessage('Hello world!', 'http://b.com'); 

//接收端
window.addEventListener('message',function(event) {
    console.log(event.data);
});

想了解window.postMessage的博友能夠看看張鑫旭老師的博客:http://www.zhangxinxu.com/wordpress/2012/02/html5-web-messaging-cross-document-messaging-channel-messaging/

方法六:WebSocket

WebSocket 是HTML5一種新的協議。它實現了瀏覽器與服務器全雙工通訊,同時容許跨域通信,是server push技術的一種很棒的實現。(不用http協議有本身的一套協議)。

在客戶端的實例:

var ws = new WebSocket('ws://127.0.0.1:8080/url'); //新建一個WebSocket對象,注意服務器端的協議必須爲「ws://」或「wss://」,其中ws開頭是普通的websocket鏈接,wss是安全的websocket鏈接,相似於https。
ws.onopen = function() {
    // 鏈接被打開時調用
};
ws.onerror = function(e) {
    // 在出現錯誤時調用,例如在鏈接斷掉時
};
ws.onclose = function() {
    // 在鏈接被關閉時調用
};
ws.onmessage = function(msg) {
    // 在服務器端向客戶端發送消息時調用
    // msg.data包含了消息
};
// 這裏是如何給服務器端發送一些數據
ws.send('some data');
// 關閉套接口
ws.close();

詳情你們仍是看紅寶書591吧。

相關文章
相關標籤/搜索