首先,何爲同源策略? 同源策略
是由Netspace提出來的一種安全策略。同源
的源
由一個URL的協議、主機、端口定義,若是這三者一致,那麼就是同源。javascript
當不一樣源的時候,哪些操做被容許呢?html
<script>
加載Javascript<link>
加載CSS<img>
加載圖片<video><audio>
加載多媒體<object><embed><applet>
加載插件<iframe>
加載任何東西哪些不容許呢?前端
XMLHttpRequest
不被容許一個頁面的源能夠修改的,經過document.domain
,好比一個頁面a.b.com
嵌入iframec.b.com
,這時候只須要把兩個頁面的document.domain
設置爲b.com
便可。java
跨域是針對前端來的,服務端是沒有跨域這個東西的,因此後臺設置一下,前端訪問時訪問一個同源頁面,而後後臺把請求的數據轉到不一樣源的頁面便可。node
前端web
var xhr = new XMLHttpRequest();
var url = 'http://localhost:3000/api'; // 向http://localhost:3000/api發出請求,獲取數據
xhr.open('GET', url);
xhr.send(null);
xhr.onreadystatechange = () => {
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) { // 若是請求成功
text.innerHTML = xhr.response;
}
}
複製代碼
同域服務器ajax
// nodeJs express
var proxy = require('http-proxy-middleware');
var app = express();
app.use('/api', proxy({target: 'http://localhost:3001/', changeOrigin: true}));
複製代碼
由於<script>
內嵌資源是容許的,因此能夠把請求的接口放在<script>
標籤上,而後附帶咱們的回調函數express
前端json
<script src="http://other.com/ajax.json?callback=myFunction"></script>
複製代碼
跨域服務器api
接口獲取到callback後,把返回的數據做爲參數傳給callback並執行。
// nodeJs express
app.get('/', function (req, res) {
var callbackName = req.query.callback;
res.send(callbackName+"({'message': 'hello world'});");
})
複製代碼
缺點
這個是HTML5的一個接口,用到了接口裏面的postMessage
方法,主要用於兩個窗口之間交換數據,不能用於與服務器交換數據。
otherWindow.postMessage(message, targetOrigin, [transfer]);
複製代碼
otherWindow
是接收方窗口的引用。通常是如下幾種方式:
而message
是支持幾乎全部形式的數據,transfer
可省略
用法:
// 父頁面
document.getElementByTagName('iframe')[0].contentWindow.postMessage({"age":10},'http://localhost:8080');
// 監聽有沒有數據返回來
window.addEventListener('message',function(e){
console.log(e)
});
複製代碼
// iframe
window.addEventListener('mesage',function(e){
if(e.origin !== 'http://localhost:8081'){
return;
}
console.log(e);
e.souce.postMessage('hello world',e.origin)
})
複製代碼
CORS須要瀏覽器和服務器同時支持,關鍵是服務器,只要服務器實現了CORS接口就能夠跨域通訊。
CORS將請求分爲兩類:簡單請求和非簡單請求。
非簡單請求的條件:
Content-type
字段是application/json
對於簡單請求,瀏覽器在頭信息裏面加一個origin
字段,說明本次請求來自哪一個源(協議+主機+端口),服務器根據這個值,決定是否贊成。若是origin
不在指定的源裏面,就會返回一個正常的HTTP迴應,可是裏面不包含Access-Control-Allow-Origin
就知道出錯了,從而拋出一個錯誤,被XMLHttpRequest
的onerror
回調函數捕獲。
這種錯誤沒法經過狀態碼判斷,有多是
200
若是源在許可範圍內,就會返回響應,並多出幾個信息字段。
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8
複製代碼
Access-Control-Allow-Origin
必須字段。若是是*
,表示接收任何域名的請求。Access-Control-Allow-Credentials
可選字段。CORS請求默認是不帶cookie和HTTP信息的,若是爲true
,代表服務器許可請求中能夠包含cookie 。除了服務器容許請求附帶cookie和HTTP信息,客戶端也必須容許var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
複製代碼
Access-Control-Expose-Headers: FooBar
該字段可選。CORS請求時,XMLHttpRequest
對象的getResponseHeader()
方法只能拿到6個基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma
。若是想拿到其餘字段,就必須在Access-Control-Expose-Headers
裏面指定。上面的例子指定,getResponseHeader('FooBar')
能夠返回FooBar字段的值。前端
var xhr = new XMLHttpRequest();
var url = 'http://localhost:3001'; // 請求的3001端口獲取數據
xhr.open('GET', url); // 與3001端口創建一個鏈接
xhr.send(null); // 發送給3001端口數據爲空
xhr.onreadystatechange = () => { // 請求狀態改變後調用這個函數
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) { // 若是請求成功
text.innerHTML = xhr.response;
}
}
複製代碼
跨域服務器
// nodeJs express
var app = express();
app.get('/', (req, res) => {
res.set('Access-Control-Allow-Origin', 'http://localhost:3000'); // 設置容許跨域的origin,容許3000端口訪問本端口(3001)
res.send("Hello world");
});
複製代碼
非簡單請求的不一樣之處在於在正式通訊以前會有一次HTTP查詢請求,成爲「預檢」請求(preflight)
前端
var url = 'http://localhost:3001';
var xhr = new XMLHttpRequest();
xhr.open('PUT', url, true);
xhr.setRequestHeader('X-Custom-Header', 'value');
xhr.send();
複製代碼
瀏覽器
瀏覽器發現這是一個非簡單請求,就會自動發出一個預檢請求。
OPTIONS /cors HTTP/1.1
Origin: http://api.bob.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
複製代碼
預檢的請求方式是OPTIONS
,表示這個請求是用來詢問的。
跨域服務器
服務器收到預檢請求後,檢查了Origin
、Access-Control-Request-Method
和Access-Control-Request-Headers
字段之後確認容許跨域請求,而後作出迴應
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain
複製代碼
Access-Control-Allow-Methods
代表服務器支持的全部跨域請求的方法。
若是預檢請求經過,之後每次的CORS請求就跟簡單請求同樣了。
缺點
非簡單請求,第一次請求會發送兩次請求
WebSocket是不受同源限制的,因此跨域什麼的就不存在了。
基本用法:
var ws = new WebSocket("wss://echo.websocket.org");
ws.onopen = function(evt) {
console.log("Connection open ...");
ws.send("Hello WebSockets!");
};
ws.onmessage = function(evt) {
console.log( "Received Message: " + evt.data);
ws.close();
};
ws.onclose = function(evt) {
console.log("Connection closed.");
};
複製代碼