跨域的理解

備註:

  1. 端口和協議的不同,只能通過後臺來解決
  2. localhost和127.0.0.1雖然都指向本機,但也屬於跨域

協議子域名主域名端口號中任意一個不相同時,都算作不同域。不同域之間相互請求資源,就算作“跨域”。

跨域並不是請求發不出去,請求能發出去,服務端能收到請求並正常返回結果,只是結果被瀏覽器攔截了。之所以會跨域,是因爲受到了同源策略的限制,同源策略要求源相同才能正常進行通信,即協議域名端口號都完全一致。

同源策略限制內容有:CookieLocalStorageIndexedDB 等存儲性內容DOM 節點``AJAX 請求不能發送

但是有三個標籤是允許跨域加載資源:

  1. <img src=XXX>
  2. <link href=XXX>
  3. <script src=XXX>

處理跨域的方法:

一、Jsonp

代碼示例:

後端:

router.get('/hehe', function (req, res, next) {
    var obj = {'0':'a','1':'b','2':'c'};
    res.send('callbackFunction('+JSON.stringify(obj)+')')//需要將對象轉爲字符串;
});

前端使用jquery的ajax的jsonp:

$.ajax({
        url: 'http://localhost:3000/index/hehe',//跨域請求的地址,也可用相對路徑js/data.js
        type: 'get',
        dataType: 'jsonp',//使用jsonp跨域請求
        jsonpCallback:'callbackFunction'
    })
    .done(function(data) {
        console.log(data)// 控制檯打印結果{0: "a", 1: "b", 2: "c"}
    })
    .fail(function() {
        console.log("error");
    });
  1. 利用<script> 元素的這個開放策略,網頁可以得到從其他來源動態產生的 JSON 數據。JSONP請求一定需要對方的服務器做支持纔可以。
    JSONP由兩部分組成:回調函數數據。回調函數是當響應到來時應該在頁面中調用的函數,而數據就是傳入回調函數中的JSON數據。

  2. JSONP和AJAX對比
    JSONP和AJAX相同,都是客戶端向服務器端發送請求,從服務器端獲取數據的方式。但AJAX屬於同源策略JSONP屬於非同源策略(跨域請求)

  3. JSONP優缺點

  • 優點:兼容性好,在很古老的瀏覽器中也可以用,簡單易用,支持瀏覽器與服務器雙向通信。 可用於解決主流瀏覽器的跨域數據訪問的問題
  • 缺點:只支持GET請求,且只支持跨域HTTP請求這種情況(不支持HTTPS)

JSON、JSONP的區別:

1. JSON返回的是一串數據、JSONP返回的是腳本代碼(包含一個函數調用)
 2. JSONP 只支持get請求、不支持post請求
 (類似往頁面添加一個script標籤,通過src屬性去觸發對指定地址的請求,故只能是Get請求)

二、CORS

  1. CORS原理

整個CORS通信過程,都是瀏覽器自動完成,不需要用戶參與。CORS通信的關鍵是服務器。只要服務器實現了CORS接口,就可以跨源通信。

核心思想:在服務器端通過檢查請求頭部的origin,從而決定請求應該成功還是失敗。

具體的方法是在服務端設置Response Header響應頭中的Access-Control-Allow-Origin爲對應的域名,實現了CORS(跨域資源共享),這裏出於在安全性方面的考慮就是儘量不要用 *

  1. CORS優缺點
  • CORS要求瀏覽器(>IE10)和服務器的同時支持,是跨域的根本解決方法,由瀏覽器自動完成。
  • 優點在於功能更加強大支持各種HTTP Method,缺點是兼容性不如JSONP

三、通過document.domain來跨子域

我們只要把http://www.example.com/a.htmlhttp://example.com/b.html這兩個頁面的document.domain都設成相同的域名就可以了。

但要注意的是,document.domain的設置是有限制的,我們只能把document.domain設置成自身或更高一級的父域,且主域必須相同。

修改document.domain的方法只適用於不同子域的框架間的交互。

四、使用window.name+iframe來進行跨域

a頁面的值傳給b頁面;

給a頁面設置window.name的值;

    window.name = 'hello world'

b頁面寫一個ifram:

<div>
    <iframe src="http://localhost:8080/config/catalog.html"></iframe>
</div>
var ifr = document.querySelector('iframe')
    ifr.onload = function() {
        console.log('跨域獲取數據', ifr.contentWindow.name);//b頁面就得到了a頁面的數據,爲:hello world
        ifr.contentWindow.close();
// 每當改變location的時候,就會重新來一次onload,所以我們希望獲取到數據之後,就直接close()
    }

window對象有個name屬性,該屬性有個特徵:即在一個窗口(window)的生命週期內,窗口載入的所有的頁面都是共享一個window.name的,每個頁面對window.name都有讀寫的權限,window.name是持久存在一個窗口載入過的所有頁面中的,並不會因新頁面的載入而進行重置

window.name的值只能是字符串的形式,這個字符串的大小最大隻能允許2M左右

五、postMessage

兩個頁面之間的相互通信;

A頁面上有一個ifram標籤B頁面:

  1. 根據id名獲得ifram的contentWindow。
// 使用$('myIFrame').contentWindow來拿到iframe中頁面的window對象,
var iframe = document.getElementById('myIFrame').contentWindow;

2.使用postMessage方法傳值。message:信息;domain:地址

iframe.postMessage(message, domain);

B頁面監聽message事件;

window.addEventListener('message', function(event) {//監聽message事件發生
    // 可以將監聽發送目標的信息來源;
    if (event.origin !== 'http://localhost:8080') return;
        console.log('B我收到了:  ' + event.data, event);
// 也可以返回給A發送消息;格式一樣:targetWindow .postMessage(message,targetOrigin,[ transfer ]);
// event.source.postMessage('B收到消息了:', event.origin);
    }, false);

window.postMessage(message,targetOrigin) 方法是html5新引進的特性,可以使用它來向其它的window對象發送消息,無論這個window對象是屬於同源或不同源
postMessage(data,origin)方法接受兩個參數

  1. data:要傳遞的數據,html5規範中提到該參數可以是JavaScript的任意基本類型或可複製的對象,然而並不是所有瀏覽器都做到了這點兒,部分瀏覽器只能處理字符串參數,所以我們在傳遞參數的時候需要使用JSON.stringify()方法對對象參數序列化,在低版本IE中引用json2.js可以實現類似效果。

  2. origin:字符串參數,指明目標窗口的源,協議+主機+端口號[+URL],URL會被忽略,所以可以不寫,這個參數是爲了安全考慮,postMessage()方法只會將message傳遞給指定窗口,當然如果願意也可以建參數設置爲"*",這樣可以傳遞給任意窗口,如果要指定和當前窗口同源的話設置爲"/"。

五、webSocket

Websocket是HTML5的一個持久化的協議,它實現了瀏覽器與服務器的全雙工通信,同時也是跨域的一種解決方案。WebSocket和HTTP都是應用層協議,都基於 TCP 協議。但是 WebSocket 是一種雙向通信協議,在建立連接之後,WebSocket 的 server 與 client 都能主動向對方發送或接收數據。同時,WebSocket 在建立連接時需要藉助 HTTP 協議,連接建立好了之後 client 與 server 之間的雙向通信就與 HTTP 無關了

六、代理

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章