這裡主要記錄在日常中對知識的學習,通過結合筆記與自身理解的方式嘗試寫下總結
文章對細節可能不會一一介紹解釋,內容僅作參考
複製程式碼
一、同源策略
同源策略/SOP(Same origin policy)是一種約定,由Netscape公司1995年引入瀏覽器,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,瀏覽器很容易受到XSS、CSFR等攻擊。所謂同源是指"協議+域名+埠"三者相同,即便兩個不同的域名指向同一個ip地址,也非同源。
同源策略限制以下幾種行為:
1.) Cookie、LocalStorage 和 IndexDB 無法讀取
2.) DOM 和 Js物件無法獲得
3.) AJAX 請求不能傳送
複製程式碼
對於 a.cat.com/src/one.htm… 進行同源檢測:
- a.cat.com/src2/one.ht… 成功
- a.cat.com/src/two/xx.… 成功
- a.cat.com/src/one.htm… 失敗(協議不同)
- b.cat.com/src/one.htm… 失敗(子域名不同)
- a.cat.com:9900/src/one.htm… 失敗(埠不同)
只要協議,域名,埠有任何一個的不同,就被當作是跨域
二、跨域的產生
跨域是指一個域下的文件或指令碼試圖去請求另一個域下的資源
1.) 資源跳轉: A連結、重定向、表單提交
2.) 資源嵌入: <link>、<script>、<img>、<frame>等dom標籤,還有樣式中background:url()、@font-face()等檔案外鏈
3.) 指令碼請求: js發起的ajax請求、dom和js物件的跨域操作等
複製程式碼
我們通常所說的跨域是狹義的,是由瀏覽器同源策略限制的一類請求場景
三、解決跨域方式
1. JSONP
通常為了減輕web伺服器的負載,我們把js、css,img等靜態資源分離到另一臺獨立域名的伺服器上,在html頁面中再通過相應的標籤從不同域名下載入靜態資源,而被瀏覽器允許
基於此原理,利用script元素的這個開放策略,網頁可以通過動態建立script,再請求一個帶參網址實現跨域通訊來得到資料
前端程式碼實現:
var script = document.createElement('script');
script.type = 'text/javascript';
// 傳參一個回撥函式名給後端,提供引數返回後呼叫的函式
script.src = 'http://www.cat.com:8080/login?user=admin&callback=handleCallback';
document.head.appendChild(script);
// 回撥執行函式 須是全域性函式
function handleCallback(res) {
alert(JSON.stringify(res));
}
複製程式碼
服務端返回程式碼如下(返回時即執行全域性函式):
//這裡的handleCallback是服務端接收到回撥函式名引數後構造生成的
handleCallback({"status": true, "user": "admin"})
複製程式碼
1.) JSONP僅支援GET請求
2.) 獲取到的是JS執行程式碼
2. 跨域資源共享 CORS
整個CORS通訊過程,都是瀏覽器自動完成,不需要使用者參與。對於開發者來說,CORS通訊與同源的AJAX通訊沒有差別,程式碼完全一樣。瀏覽器一旦發現AJAX請求跨源,就會自動新增一些附加的頭資訊,有時還會多出一次附加的請求,但使用者不會有感覺。
普通跨域請求:只服務端設定Access-Control-Allow-Origin即可,前端無須設定,若要帶cookie請求:前後端都需要設定。因此,實現CORS通訊的關鍵是伺服器。只要伺服器實現了CORS介面,就可以跨源通訊
CORS要求瀏覽器(>IE10)和伺服器的同時支援,是跨域的根本解決方法,由瀏覽器自動完成 前端程式碼實現:
var xhr = new XMLHttpRequest() //IE8/9需用window.XDomainRequest相容
// 前端設定是否帶cookie
xhr.withCredentials = true
xhr.open('post', 'http://www.domain2.com:8080/login', true)
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
xhr.send('user=admin')
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
alert(xhr.responseText);
}
}
複製程式碼
服務端程式碼實現:
//允許跨域訪問的域名:若有埠需寫全(協議+域名+埠),若沒有埠末尾不用加'/'
response.setHeader("Access-Control-Allow-Origin", "http://www.domain1.com")
// 允許前端帶認證cookie:啟用此項後,上面的域名不能為'*',必須指定具體的域名,否則瀏覽器會提示
response.setHeader("Access-Control-Allow-Credentials", "true")
// 提示OPTIONS預檢時,後端需要設定的兩個常用自定義頭
response.setHeader("Access-Control-Allow-Headers", "Content-Type,X-Requested-With")
複製程式碼