1、什么是同源策略
同源策略是瀏覽器出于安全性的考量而制定的策略,默認情況下,XHR對象只能訪問與包含它的頁面位于同一個域中的資源,即限制了來自不同源的"document"或腳本對當前"document"讀取或設置某些屬性。
我們知道URL(document.URL)由協議(http/https/file/ftp)、域名(doucment.domain)、端口(port:3000/4000/80/8080)、還有路徑組成,如果兩個URL的協議、域名、端口(URL組成部分前3個)相同,則表示他們同源。
a)a.b.com a.b.com/a.html 同源,域相同。
b)b.com a.b.com 不同源,域不同。
c)a.b.com:8080 a.b.com/3000 不同源,端口不同。
d)http://a.b.com https://a.b.com 不同源,協議不同
2、 什么是跨域?跨域有幾種實現形式
跨域:跨域顧名思義就是突破同源策略的限制,去不同的域下訪問數據。
實現形式:jsonp、CORS:跨域資源共享(Cross-Origin Resource Sharing)、降域、postMessage()
3、JSONP 的原理是什么
在html下引入script標簽是可以請求不同源的數據。那么也就是說同源策略并沒有對script的src進行監測,而且script的特性是在頁面加載時會訪問script的src,那么我們可以將這個src想象成一個簡單的get請求,通過訪問這個地址,我們可以配合后端對路由進行參數配置,使這段訪問的src中加入一些參數,從而靈活的從后端調取數據。我們甚至可以通過訪問這個src來調用客戶端里存在的方法,比如我們有一個function:
function jsonFn(param) { //do sth }
<script src='http://a.xx.com:3000/getSth?callback=jsonFn></script>
//與前面的jsonFn對應,注意先后順序以防報錯: jsonFn is not defined.
//server-side - routes
app.get("/getSth", function(){
let data = req.query.callback + '(param)' ;//提取問號后callback鍵值對兒的值并加工成函數調用形式的字符串。
res.send(data);
});
優缺點:
優點:它的兼容性更好,在更加古老的瀏覽器中都可以運行。
缺點:它只支持GET請求而不支持POST等其它類型的HTTP請求。
4、CORS是什么
CORS是一個W3C標準,全稱是”跨域資源共享”(Cross-origin resource sharing)。它是一種AJAX跨域請求資源的方式,對于開發者來說,CORS通信與AJAX通信沒有差別。
它的實現方式很簡單,并且由瀏覽器自動處理,不需要做額外的工作。當我們使用 XMLHttpRequest 發送請求時,假如瀏覽器發現請求不符合同源策略,就會給該請求加一個請求頭:Origin,后臺在處理時,假如確定接收請求就會在返回結果中加一個響應頭:Access-Control-Allow-Origin,再由瀏覽器自己判斷響應頭中有沒有包含Origin的值,如果有瀏覽器就會處理響應,我們就可以拿到數據,如果不包含瀏覽器就會拒絕,此時我們就無法拿到響應數據。
優缺點:
優點:可以處理GET、POST等所有HTTP請求,不像JSONP那樣只支持GET請求。使用時簡單,只要服務器實現了CORS接口,就可以跨源通信。應該說CORS是最好的處理跨域的方式,它是跨域處理方案未來的趨勢。
缺點:響應的它的兼容性較差,IE瀏覽器不能低于IE10。
5、降域
與JSONP 和 CORS 不同,降域這種解決方案只適用于主域相同,子域不同的用場景,一般主要用于頁面有 iframe 的情況。具體的原理很簡單:兩個頁面都要通過JS來強制設置 document.domain 為基礎的主域,就實現了降域跨域。
6、postMessage
postMessage()是HTML5引入的新API,主要被用來解決跨域和跨窗口消息傳遞等問題,它的應用場景相對廣泛,可以被用于解決以下問題:頁面和其打開的新窗口的數據傳遞、多窗口之間消息傳遞、頁面與嵌套的iframe消息傳遞、上面三個問題的跨域數據傳遞。
otherWindow.postMessage(message, targetOrigin, [transfer]);
我們通過給postMessage()方法設置參數來允許來自不同源的腳本采用異步方式進行有限的通信,可以實現跨文本檔、多窗口、跨域消息傳遞。postMessage有兩個參數。
message,將要發送到其他 window的數據。
targetOrigin,通過窗口的origin屬性來指定哪些窗口能接收到消息事件,其值可以是字符串“*”(表示無限制)或者一個URI。