跨域簡單的理解就是JavaScript同源策略的限制。是出於安全的考慮,a.com域名下的js不能操做b.com或者c.com域名下的對象。
當協議、子域名、主域名、端口號中任意一個不相同時,都算做不一樣域。不一樣域之間相互請求資源,就算叫「跨域」。javascript
一個正常的域名地址組成(圖片來自網絡資源):html
注意:跨域不是請求發佈出去,請求能夠正常發出,服務器也能收到並返回結果,只是結果被瀏覽器所攔截了。java
附上一張參考圖,便於你們深刻理解(圖片來自網絡資源)web
同源策略限制了從同一個源加載的文檔或腳本如何與來自另外一個源的資源進行交互。這是一個用於隔離潛在惡意文件的重要安全機制。這是一種保護用戶信息,防止惡意身份僞造的一種安全機制。
同源策略限制的內容:ajax
3.DOM 沒法得到。json
不過,有幾個標籤卻能夠容許跨域請求資源(能夠做爲解決跨域的一種方案)。跨域
1.<img src="xxxx" alt="">
2.<link rel="stylesheet" href="xxx">
3.<script src="xxx"></script>
JSONP是跨域通訊最經常使用的方法,其最大的特色就是簡單適用、兼容性好,可用於解決主流瀏覽器的跨域數據訪問的問題。 缺點是僅支持get方法具備侷限性。 它的基本思想是,在網頁中添加一個<script>標籤,像服務器請求JSON數據。它須要服務器端的配合,服務器收到請求後,將數據放在指定名字的回調函數中傳回來。
<script type="text/javascript"> function foo(data) { console.log(data.msg); } </script> <script type="text/javascript" src="http://xxx.com/xx?callback=foo"></script>
注意,該請求的查詢字符串有一個callback參數,用來指定回調函數的名字,這對於JSONP是必需的。瀏覽器
因爲<script>元素請求的腳本,直接做爲代碼運行。這時,只要瀏覽器定義了foo函數,該函數就會當即調用。做爲參數的JSON數據被視爲JavaScript對象,而不是字符串,所以避免了使用JSON.parse的步驟。
JSONP都是GET和異步請求的,不存在其餘的請求方式和同步請求,且jQuery默認就會給JSONP的請求清除緩存緩存
$.ajax({ url: "http://xxx/xx", dataType: "jsonp", type: "get",//能夠省略 jsonpCallback: "fn",//->自定義傳遞給服務器的函數名,而不是使用jQuery自動生成的,可省略 jsonp: "jsonp",//->把傳遞函數名的那個形參callback變爲jsonp,可省略 success: function (data) { console.log(data); } });
CORS是跨源資源分享(Cross-Origin Resource Sharing)的縮寫。它是W3C標準,是跨源AJAX請求的根本解決方法。相比JSONP只能發GET請求,CORS容許任何類型的請求。缺點是兼容性不如JSONP。安全
CORS要求瀏覽器(>IE10)和服務器的同時支持,是跨域的根本解決方法,由瀏覽器自動完成。所以,實現CORS通訊的關鍵是服務器。只要服務器實現了CORS接口,就能夠跨源通訊。
服務器端作的小改動:
header("Access-Control-Allow-Origin:*");
header("Access-Control-Allow-Methods:POST,GET");
//在服務器端設置同源策略地址
router.get("/userlist",function (req, res,next) { var user = { name: 'Mr.Cao', gender: 'male', career: 'IT Education' }; res.writeHeader(200, {"Access-Control-Allow-Origin": 'http://localhost:63342'}); res.write(JSON.stringify(user)); res.end(); });
在響應頭上添加 Access-Control-Allow-Origin 屬性,指定同源策略的地址。同源策略默認地址是網頁的自己。只要瀏覽器檢測到響應頭帶上了CORS,而且容許的源包括了本網站,那麼就不會攔截請求響應。
WebSocket是一種通訊協議,使用ws://(非加密)和wss://(加密)做爲協議前綴。該協議不實行同源政策,只要服務器支持,就能夠經過它進行跨源通訊。
下面是一個例子,瀏覽器發出的WebSocket請求的頭信息
GET /chat HTTP/1.1 Host: server.example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== Sec-WebSocket-Protocol: chat, superchat Sec-WebSocket-Version: 13 Origin: http://example.com上面代碼中,有一個字段是Origin,表示該請求的請求源(origin),即發自哪一個域名。
正是由於有了Origin這個字段,因此WebSocket纔沒有實行同源政策。由於服務器能夠根據這個字段,判斷是否許可本次通訊。若是該域名在白名單內,服務器就會作出以下回應。
若是兩個網頁不一樣源,就沒法拿到對方的DOM。典型的例子是iframe窗口和window.open方法打開的窗口,它們與父窗口沒法通訊。
對於徹底不一樣源的網站,目前有三種方法,能夠解決跨域窗口的通訊問題。
6.1 片斷識別符
片斷標識符(fragment identifier)指的是,URL的#號後面的部分,好比 http://xxx.com/x.html#fragmen...。若是隻是改變片斷標識符,頁面不會從新刷新。
父窗口能夠把信息,寫入子窗口的片斷標識符。
var src = originURL + '#' + data; document.getElementById('myIFrame').src = src;
子窗口經過監聽hashchange事件獲得通知。
window.onhashchange = checkMessage; function checkMessage() { var message = window.location.hash; // ... }
6.2 window.name
瀏覽器窗口有window.name屬性。這個屬性的最大特色是,不管是否同源,只要在同一個窗口裏,前一個網頁設置了這個屬性,後一個網頁能夠讀取它。
父窗口先打開一個子窗口,載入一個不一樣源的網頁,該網頁將信息寫入window.name屬性。
window.name = data;
接着,子窗口跳回一個與主窗口同域的網址。
location = 'http://parent.url.com/xxx.html';
而後,主窗口就能夠讀取子窗口的window.name了。
var data = document.getElementById('myFrame').contentWindow.name;
這種方法的優勢是,window.name容量很大,能夠放置很是長的字符串;缺點是必須監聽子窗口window.name屬性的變化,影響網頁性能。
6.3 window.postMessage
上面兩種方法都屬於破解,HTML5爲了解決這個問題,引入了一個全新的API:跨文檔通訊 API(Cross-document messaging)。
這個API爲window對象新增了一個window.postMessage方法,容許跨窗口通訊,不論這兩個窗口是否同源。
舉例來講,父窗口http://aaa.com向子窗口http://bbb.com發消息,調用postMessage方法就能夠了。
var popup = window.open('http://bbb.com', 'title'); popup.postMessage('Hello World!', 'http://bbb.com');
postMessage方法的第一個參數是具體的信息內容,第二個參數是接收消息的窗口的源(origin),即"協議 + 域名 + 端口"。也能夠設爲*,表示不限制域名,向全部窗口發送。
子窗口向父窗口發送消息的寫法相似。
window.opener.postMessage('Nice to see you', 'http://aaa.com');
父窗口和子窗口均可以經過message事件,監聽對方的消息。
window.addEventListener('message', function(e) { console.log(e.data); },false);
message事件的事件對象event,提供如下三個屬性。
event.source:發送消息的窗口 event.origin: 消息發向的網址 event.data: 消息內容
七 、處理跨域方法五-document.domain
Cookie 是服務器寫入瀏覽器的一小段信息,只有同源的網頁才能共享。可是,兩個網頁一級域名相同,只是二級域名不一樣,瀏覽器容許經過設置document.domain共享 Cookie。
舉例來講,A網頁是http://w1.example.com/a.html,B網頁是http://w2.example.com/b.html,那麼只要設置相同的document.domain,兩個網頁就能夠共享Cookie。
document.domain = 'example.com';
如今,A網頁經過腳本設置一個 Cookie。
document.cookie = "test1=hello";
B網頁就能夠讀到這個 Cookie。
var allCookie = document.cookie;
注意,這種方法只適用於 Cookie 和 iframe 窗口,LocalStorage 和 IndexDB 沒法經過這種方法。