什麼是跨域?
廣義的跨域:跨域是指一個域下的文檔或腳本試圖去請求另一個域下的資源,這裡跨域是廣義的。
- 資源跳轉: A連結、重定向、表單送出
- 資源嵌入: 、
狹義的跨域:常說的一種跨域,由浏覽器同源政策限制的一類請求場景。
什麼是同源政策?
同源政策/SOP(Same origin policy)是一種約定,由Netscape公司1995年引入浏覽器,它是浏覽器最核心也最基本的安全功能,如果缺少了同源政策,浏覽器很容易受到XSS、CSFR等攻擊。所謂同源是指"協定+域名+端口"三者相同,即便兩個不同的域名指向同一個ip位址,也非同源。
同源政策限制以下幾種行為:
- Cookie、LocalStorage 和 IndexDB 無法讀取
- DOM 和 Js對象無法獲得
- AJAX 請求不能發送
常見跨域場景:
URL 說明 是否允許通信
http://www.domain.com/a.js
http://www.domain.com/b.js 同一域名,不同檔案或路徑 允許
http://www.domain.com/lab/c.js
http://www.domain.com:8000/a.js
http://www.domain.com/b.js 同一域名,不同端口 不允許
http://www.domain.com/a.js
https://www.domain.com/b.js 同一域名,不同協定 不允許
http://www.domain.com/a.js
http://192.168.4.12/b.js 域名和域名對應相同ip 不允許
http://www.domain.com/a.js
http://x.domain.com/b.js 主域相同,子域不同 不允許
http://domain.com/c.js
http://www.domain1.com/a.js
http://www.domain2.com/b.js 不同域名 不允許
跨域解決方案 -----詳情:https://segmentfault.com/a/1190000011145364
1、 通過jsonp跨域
2、 document.domain + iframe跨域
3、 location.hash + iframe
4、 window.name + iframe跨域
5、 postMessage跨域
6、 跨域資源共享(CORS)
7、 nginx代理跨域
8、 nodejs中間件代理跨域
9、 WebSocket協定跨域
一、CORS(Cross-origin resource sharing 跨域資源共享)
它允許浏覽器向跨源伺服器,發出XMLHttpRequest請求,進而克服了AJAX隻能同源使用的限制。
CORS(Cross-Origin Resource Sharing)跨域資源共享,定義了必須在通路跨域資源時,浏覽器與伺服器應該如何溝通。CORS背後的基本思想就是使用自定義的HTTP頭部讓浏覽器與伺服器進行溝通,進而決定請求或響應是應該成功還是失敗。cors依附于AJAX,通過添加HTTP Hearder部分字段請求與擷取有權限通路的資源。
整個CORS通信過程,都是浏覽器自動完成,不需要使用者參與。對于開發者來說,CORS通信與同源的AJAX通信沒有差别,代碼完全一樣。浏覽器一旦發現AJAX請求跨源,就會自動添加一些附加的頭資訊,
(Origin:http://www.ajdf.com:80 包括請求頁面的源資訊:協定 域名 端口号)有時還會多出一次附加的請求,但使用者不會有感覺。
是以,實作CORS通信的關鍵是伺服器。隻要伺服器實作了CORS接口,就可以跨源通信。伺服器根據這個頭部資訊來決定是否給予響應。
如果伺服器認為這個請求可以接受,就設定Access-Control-Allow-Origin **(與請求的)相同的 源資訊或者 ***
如果沒有這個頭部,或者有這個頭部但源資訊不比對,浏覽器就駁回(撤銷?)請求。
<script type="text/javascript">
var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest相容
xhr.withCredentials = true; // 前端設定是否帶cookie
xhr.open("GET", "http://segmentfault.com/u/ccd/",true); // 其他域的絕對路徑,也就是你要跨域通路的接口位址
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
alert(xhr.responseText);
}
};
</script>
伺服器端對于CORS的支援,主要就是通過設定Access-Control-Allow-Origin來進行的。如果浏覽器檢測到相應的設定,就可以允許Ajax進行跨域的通路。
使用場景:對伺服器端的資源要進行一些操作的。
二、JSONP(json with padding 填充式json)
利用了使用src引用靜态資源時不受跨域限制的機制。其實就是被包含在函數調用中的JSON。
JSONP由兩部分組成:回調函數和資料。回調函數是當響應到來時應該在頁面中調用的函數,而資料就是傳入回調函數中的JSON資料。
jsonp主要在用戶端搞一個回調做一些資料接收與操作的處理,并把這個回調函數名告知服務端,而服務端需要做的是按照javascript的文法把資料放到約定好的回調函數之中即可。
原生:
<script>
// 回調執行函數
function handleCallback(res) {
alert(JSON.stringify(res));
}
</script>
// 傳參一個回調函數名給後端,友善後端傳回時執行這個在前端定義的回調函數
<script src="http://www.a.com:8080/login?user=admin&callback=handleCallback" type='text/javascript'></script>
// vue:
this.$http.jsonp('http://www.domain2.com:8080/login', {
params: {},
jsonp: 'handleCallback'
}).then((res) => {
console.log(res);
})
使用場景:相容低版本浏覽器。
CORS和JSONP的對比:-----CORS更為先進、友善和可靠。
- JSONP的主要優勢在于對浏覽器的支援較好;雖然目前主流浏覽器支援CORS,但IE10以下不支援CORS。jsonp不需要依賴ajax請求受同源政策限制。而是請求完以回調函數的方式回傳結果。
- jsonp隻能實作get請求。隻支援跨域http請求的情況,不能解決跨域之間頁面的js調用問題。CORS支援所有類型的HTTP請求,功能完善。(這點JSONP被完虐,但大部分情況下GET已經能滿足需求了)
- JSONP的錯誤處理機制并不完善,我們沒辦法進行錯誤處理;而CORS可以通過onerror事件監聽錯誤,可以使用普通的XMLHttpRequest發起請求和獲得資料,并且浏覽器控制台會看到報錯資訊,利于排查。
- JSONP隻會發一次請求;而對于複雜請求,CORS會發兩次請求。
參考:https://www.cnblogs.com/chengdabelief/p/6685446.html
參考:https://www.zhihu.com/question/41992168/answer/217903179
參考:https://www.cnblogs.com/Koaler/p/11892205.html