詳解Web跨域和同源,超全~(8種解決方式)

跨域和同源


跨域,是指瀏覽器不能執行其他網站的腳本。它是由瀏覽器的同源策略造成的,是瀏覽器對JavaScript實施的安全限制。

1.javascript的同源策略(Same-Origin Policy)

1.1 在同源策略下,瀏覽器限制的請求:

  • Ajax請求發送不出去
  • DOM 和 JS 對象無法獲取
  • Cookie、LocalStorage 和 IndexDB 無法讀取

1.2 允許通信的情況:

  • 同一來源指的是協議+域名+端口號

協議如:http,ftp https
端口名如:80(http協議的默認端口:80,https:協議的默認端口是8083)

  • 同域下的不同文件夾

1.3 不允許的情況:

  • 域名和域名對應的IP
    在這裏插入圖片描述
  • 主域相同,子域不同
    在這裏插入圖片描述
  1. 主域:一般是域名後綴,如:baidu.com
    子域:一般是前綴,如:www.
  2. 如果是協議和端口造成的跨域問題“前臺”是無能爲力的

2. 跨域問題的解決方案

  • 2.1 服務端CORS方法

    CORS——跨域資源共享"(Cross-origin resource sharing)

    以一個例子來說明:
    • 服務器的888端口發送了一個html
      在這裏插入圖片描述
    • 但是在html裏面向8887端口發送了請求【跨域了】
      在這裏插入圖片描述
    • 瀏覽器訪問localhost:8888,控制檯出現報錯,cors policy阻止了這個跨域請求,因爲沒有設置’Access-Control-Allow-Origin這個請求頭
      在這裏插入圖片描述
    • 這個時候其實請求是發出去了的,但是,瀏覽器看到response頭裏面沒有acar的請求頭,知道了這個跨域請求其實是不被允許的,所以就會攔截他,【瀏覽器跨域限制】
      在這裏插入圖片描述
    • 設置響應頭了以後:response.writeHead(200, { “Access-Control-Allow-Origin”: “*” });就沒有報錯了,請求成功
      在這裏插入圖片描述
優點
1、CORS支持所有類型的HTTP請求。
2、 使用CORS,開發者可以使用普通的XMLHttpRequest發起請求和獲得數據,比起JSONP有更好的錯誤處理。

2.2 客戶端解決方案

2.2.1 JSONP(JSON with padding)
原理

有三種資源是可以與頁面本身不同源的。它們是:js腳本,css樣式文件,圖片,像淘寶等大型網站,肯定會將這些靜態資源放入cdn()中,然後在頁面上連接,如下所示,所以它們是可以鏈接訪問到不同源的資源的。

CDN(Content delivery networks)緩存,網關緩存、【反向代理緩存】

  • 1)<script type="text/javascript" src="某某cdn地址" ></script>

  • 2)<link type="text/css" rel="stylesheet" href="某個cdn地址" />

  • 3)<img src="某個cdn地址" alt=""/>

    而jsonp就是利用了script標籤的src屬性是沒有跨域的限制的,通過創建script標籤(link,img),通過src(ref)來訪問服務器,這個沒有跨域的限制從而達到跨域訪問的目的。

    一個例子:
  • jquery也支持jsonp的實現方式
    callback是必須的,callback是什麼值要跟後臺拿。獲取到的jsonp數據格式如下:
    在這裏插入圖片描述

    • 獲取到的jsonp數據格式如下:上面的數據中,flightHandler就是那個padding.
      在這裏插入圖片描述

不足

  • 只能使用get方法】,不能使用post方法:script,link, img 等等標籤引入外部資源,都是 get 請求的,那麼就決定了 jsonp 一定是 get 的。

  • 沒有關於 JSONP 調用的錯誤處理】。如果動態腳本插入有效,就執行調用;【如果無效,就靜默失敗】。失敗是沒有任何提示的。例如,不能從服務器捕捉到 404 錯誤,也不能取消或重新開始請求。

2.2.2 window.name + iframe 跨域

當iframe的頁面跳到其他地址時,其window.name值保持不變,並且可以支持非常長的 name 值(2MB)。

2.2.3 location.hash + iframe 跨域
  • 而location.hash其實就是url的錨點。比如https://www.geekjc.com#geekjcg的網址打開後,在控制檯輸入location.hash就會返回#geekjc的字段。

  • 如果index頁面要獲取遠端服務器的數據,動態的插入一個iframe,將iframe的src執行服務器的地址,這時候的top window 和包裹這個iframe的子窗口是不能通信的

  • 數據當做改變後的路徑的hash值加載路徑上,然後就可以通信了。將數據加在index頁面地址的hash上, index頁面監聽hash的變化,h5的hashchange方法

    其實location.hash和window.name都是差不多的,都是利用全局對象屬性的方法,然後這兩種方法和jsonp也是一樣的,就是隻能夠實現get請求

2.2.4 document.domain+iframe的設置

(只有在主域相同的時候才能使用該方法)

原理
  • 瀏覽器中不同域的框架之間是不能進行js的交互操作的。但是不同的框架之間【父子或同輩】,是能夠獲取到彼此的【window對象】的
  • 可以通過document.domain把兩個頁面的domain都設成相同的域名,但這個相同的域名必須是兩個頁面【公共的主域
實現
2.2.5 HTML5的postMessage
  • 在需要發送消息的源窗口調用postMessage方法即可發送消息。其中.源窗口可以是全局的window對象,也可以是以下類型的窗口:iframe,window.open,window.parent.
  • 發送消息:找到源window對象後,即可調用postMessage API向目標窗口發送消息:
    • 1、msg, 將要發送的消息,可以使一切javascript參數,如字符串,數字,對象,數組等。
    • 2、targetOrigin,這個參數稱作“目標域”,注意,是目標域不是本域!比如,你想在2.com的網頁上往1.com網頁上傳消息,那麼這個參數就是“http://1.com/”
  • 接收消息:那目標窗口要怎麼接收傳過來的數據呢,只要監聽window的message事件就可以接收了。
    • message事件監聽函數接收一個參數,Event對象實例,該對象有三個屬性:

data : 消息
origin:消息的來源地址
source:發送消息窗口的window對象引用

2.2.6 WebSocket協議跨域
  1. WebSocket protocol是HTML5一種新的協議。它實現了瀏覽器與服務器全雙工通信,同時允許跨域通訊
  2. 我們使用Socket.io/它很好地封裝了webSocket接口,提供了更簡單、靈活的接口,也對不支持webSocket的瀏覽器提供了向下兼容。也可以使用原生Websocket。
2.2.7 node代理跨域
  1. node中間件實現跨域代理,是通過啓一個代理服務器,實現數據的轉發,這裏是代理所有path以“/”開頭的請求,代理到target上:
    在這裏插入圖片描述
  2. 也可以通過設置cookieDomainRewrite參數修改響應頭中cookie中域名,實現當前域的cookie寫入,方便接口登錄認證
2.2.8 nginx反向代理跨域
  1. nginx配置解決iconfont跨域此時可在nginx的靜態資源服務器中加入以下配置。
  2. nginx反向代理接口跨域
跨域原理

同源策略是瀏覽器的安全策略,不是HTTP協議的一部分。服務器端調用HTTP接口只是使用HTTP協議,不會執行JS腳本,不需要同源策略,也就不存在跨越問題。

實現思路

通過nginx配置一個【代理服務器(域名與domain1相同,端口不同)】做跳板機,【反向代理訪問domain2接口】,並且可以順便【修改cookie中domain】信息,方便當前域cookie寫入,實現【跨域登錄】。
在這裏插入圖片描述
前端訪問的是domain1,不存在跨域
在這裏插入圖片描述
後臺寫上setcookies,前端可以拿到cookies
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章