在先後端通訊時,有時會遇到跨域問題,接下來將從如下幾個方面進行跨域詳解。javascript
1. 爲何會有跨域問題?java
2. 什麼是同源策略?jquery
3.先後端通訊方式有哪些?web
4.解決跨域通訊的方式有哪些?ajax
5.解決跨域方式詳細說明express
爲何會有跨域問題?json
答:是因爲瀏覽器的同源策略。後端
什麼是同源策略?api
答:同源策略(Same origin policy)是一種約定,它是瀏覽器最核心也最基本的安全功能。 同源策略限制了從一個源加載的文件或腳本如何與另外一個源的資源進行交互。這是一個用於隔離潛在惡意文件的安全機制。跨域
那什麼是源呢?源就是由:協議 + 域名 + 端口號 組成;
只有同源的時候才能夠完成通訊;若是是非同源的話,瀏覽器會在控制檯中報一個異常,提示拒絕訪問。
同源策略的限制:
一、cookie,localstorage和IndexDB沒法讀取;
二、DOM沒法獲取;
三、Ajax請求不能發送
先後端通訊方式有哪些?
答:ajax; webSocket; CORS(跨域資源共享)
解決跨域通訊的方式有哪些?
答:jsonp; webSocket; CORS; Hash; postMessage;
解決跨域方式詳細說明
1--jsonp
原理:利用<script>元素的開放策略,能夠加載其餘源的文件和動態產生的json,可是JSONP請求必定要對方的服務器支持纔可使用。
具體寫法:
第一種跟第三種寫法的原理是同樣的,都是利用script標籤,建立回調函數fn,把那個跨域的api接口地址賦給script的src,並把新建的函數做爲參數傳遞給接口(?callback=fn),後端接受請求後,會把傳進來的函數名fn和查詢到的數據組合(fn({data:「張三」}))後返回;
第二種寫法是利用jQuery的jsonp請求,在ajax請求時指定服務器返回的數據類型,可是jsonp只支持get請求,不支持post;
<!-- 客戶端 --> <script> function call(data){ alert(data) } // 第一種:動態添加script標籤 function createScript(src){ var script = document.createElement("script"); script.setAttribute("type","text/javascript"); script.src = src; document.body.appendChild(script); } createScript("http://127.0.0.1:3000/?callback=call"); // 第二種:jquery的jsonp方式 $.ajsx({ url: "http://127.0.0.1:3000/", type: "GET", //jsonp只支持get請求,不支持post dataType: "jsonp", //指定服務器返回的類型 success: function(data){ console.log(JSON.stringify(data)); } }) </script> <!-- 第三種:直接使用script標籤 --> <script type="text/javascript" src="http://127.0.0.1:3000?callback=call"></script>
<!-- 服務端 --> app.get('/',function(req,res){ var callback = req.query.callback; var data = {nama:"Marry"}; res.send(callback+"("+data+")"); res.end(); });
2--webSocket
WebSocket 簡介:
是 HTML5 開始提供的一種在單個 TCP 鏈接上進行全雙工通信的協議。
WebSocket使得客戶端和服務器端的通訊更加方便,容許服務端主動向客戶端返回數據,使用WebSocket,客戶端和服務器端只需創建一次「握手」,就能夠創建永久鏈接,並進行雙向數據請求。
WebSocket的寫法:
// 瀏覽器發出的WebSocket請求的頭信息。 GET /chat HTTP/1.1 Host: server.example.com Upgrade: websocket //Upgrade 字段必須設置 Websocket,表示但願升級到 Websocket 協議。 Connection: Upgrade //Connection 必須設置 Upgrade,表示客戶端但願鏈接升級。 Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== Sec-WebSocket-Protocol: chat, superchat Sec-WebSocket-Version: 13 //表示支持的 Websocket 版本 Origin: http://example.com //表示在瀏覽器中發起此 Websocket 鏈接所在的頁面
瀏覽器請求頭中有「Origin」,表示發起鏈接的源,正是因爲有這個字段,才能夠進行非同源通訊,服務器接收到請求後,會根據這個字段判斷是否容許通訊,若是該地址在容許的通訊的名單中,則服務器會返回如下信息。
// 服務器迴應 HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: fFBooB7FAkLlXgRSz0BT3v4hq5s= Sec-WebSocket-Location: ws://example.com/
3--CORS
CORS簡介:
CORS全稱是「跨域資源共享」,它容許瀏覽器向不一樣源(協議+域名+端口號)的服務器發送XMLHttpRequest請求,從而解決了ajax只能同源訪問的限制。
CORS須要客戶端和服務器都配置才能夠正常使用,CORS的通訊與Ajax通訊對於開發者來講代碼都是同樣的,只是當瀏覽器識別到是Ajax請求時,會自動給請求的頭信息裏增長一些信息,但用戶是發覺不到的。
所以,實現CORS通訊的關鍵是服務器端的接口要支持CORS,只要實現了CORS接口,就能夠進行跨域通訊了。
CORS寫法:
// 服務器端設置 var express = require('express'); var app = express(); var allowCrossDomain = function (req, res, next) { res.header('Access-Control-Allow-Origin', 'http://localhost:3001'); res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE'); res.header('Access-Control-Allow-Headers', 'Content-Type'); next(); } app.use(allowCrossDomain);
CORS參數介紹:
Access-Control-Allow-Methods:該字段必需,它的值是逗號分隔的一個字符串,代表服務器支持的全部跨域請求的方法。注意,返回的是全部支持的方法,而不單是瀏覽器請求的那個方法。這是爲了不屢次"預檢"請求。
Access-Control-Allow-Origin:該字段必填。它的值要麼是請求時Origin字段的具體值,要麼是一個*,表示接受任意域名的請求。
Access-Control-Expose-Headers:該字段可選。CORS請求時,XMLHttpRequest對象的getResponseHeader()方法只能拿到6個基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。若是想拿到其餘字段,就必須在Access-Control-Expose-Headers裏面指定。
注意事項:
使用cors時須要傳遞cookie,雖然能夠跨域通訊,但cookie依然遵循同源策略,只有用服務器設置的cookie才能夠獲取到並上傳,其餘域名的不能夠。
4--Hash
Hash寫法:
// 當前頁面A經過iframe或者frame嵌入了頁面B,經過hash實現A、B頁面通訊 //A中代碼 var B = document.getElementsByTagName('iframe'); var data = JSON.stringify({name:"zhangsan"}) B.src = B.src + data;//data是要傳遞的參數,已轉換成字符串 //B中代碼 window.onhashchange = function(){//經過onhashchange監聽hash的變化 var dataVal = window.location.hash; }
Hash主要是利用onhashchange 這個事件監聽hash的變化,來獲取傳遞的參數。
5--postMessage
postMessage簡介:
在HTML5中新增了postMessage方法,postMessage能夠實現跨文檔消息傳輸(Cross Document Messaging),Internet Explorer 8, Firefox 3, Opera 9, Chrome 3和 Safari 4都支持postMessage。
//窗口A(http://a.com)向跨域的窗口B(http://b.com)通訊 //A中代碼 a.postMessage("data","http://b.com");//第一個參數爲要傳遞的數據;第二個參數是要通訊的源。 //B中代碼 b.addEventListener("message", function(event){ console.log(event.origin,event.source,event.data)//能夠獲取到發送消息的源,發送消息的窗口對象,還有傳遞的數據
})
postMessage主要是用postMessage方法和message事件相結合完成跨域通訊的。
以上就是同源策略和跨域通訊的相關解釋,有不對的地方,歡迎你們指正!
-THE END-