之前對於跨域相關的知識一致都很零碎,正好現在的程式碼中用到了跨域相關的,現在來對這些知識做一個彙總整理,方便自己檢視,說不定也可能對你有所幫助。
本篇主要內容如下:
- 瀏覽器同源策略
- http 請求跨域
- http 請求跨域解決辦法
- cookie 機制
- 如何共享 cookie
瀏覽器同源策略
相信很多人在 web 入門時,都被跨域問題折磨的死去活來。要想完全掌握跨域就得知道為什麼會有跨域這個問題出現。
簡單來說跨域問題是因為瀏覽器的同源策略導致的。那瀏覽器為什麼要有同源策略呢?
當然是為了安全。沒有同源策略限制的瀏覽器環境是非常危險的(即使有了同源策略也不是百分百安全),有興趣的可以去了解了解CSRF和XSS攻擊。
所謂的“同源”指的是“三個相同”:
- 協議相同。不能一個是 http 協議,一個是 https
- 域名相同
- 埠相同
如果非同源頁面有以下限制:
- LocalStore 和 IndexDB 無法讀取。這兩個顯然是不能讀取的,但是 cookie 有點不一樣,放在後面單獨說明
- DOM 無法獲取,比如如法在頁面 A 中通過 iframe 獲取異源頁面 B 的 DOM
- AJAX 請求無法讀取(可以傳送請求,但是無法讀取到請求結果。比如在頁面 A 中請求異源介面 B,請求會正常發出處理,但是在頁面 A 中無法獲取請求結果,除非響應頭 Access-Control-Allow-Headers 中允許了頁面 A 的源,這樣就能讀取到結果)
但是這裡有個例外,所有帶“src”屬性的標籤都可以跨域載入資源,不受同源策略的限制,這樣你應該可以想到一個比較古老的跨域解決方案(JSONP),同時這個特性也會被用作 CSRF 攻擊。
http 請求跨域
在前端開發中經常會遇到跨域的問題,比如前後端分離中前後端部署在不同的埠上,或者在前端頁面中需要向另外一個服務請求資料,這些都會被跨域所阻擋。
目前主要有以下幾種辦法解決跨域問題:
- 關閉瀏覽器同源檢查
這個太暴力,也太不安全了,不用考慮。
- jsonp 實現跨域請求
前面說過了瀏覽器對於帶 src 屬性的標籤都可以跨域的。因此 jsonp 的實現流失利用了這個特性,在頁面中動態插入一個<script>
標籤,然後他的 src 屬性就是介面呼叫地址,這樣就能訪問過去了,然後再講返回內容特殊處理成立即執行的函式,這樣就看起像進行了一次跨域請求。之所以不推薦這種方式,主要有以下兩個原因:
- 實現複雜,且需要前後臺同時修改才能實現
- 只能進行 get 請求
- 伺服器設定執行跨域
這種方法只需要後臺做處理便能實現跨域,前面說的 http 跨域請求是能夠發出去的,只是不能接收,那我們只要在響應頭Access-Control-Allow-Headers
中加入允許請求的地址即可,以,
分隔,同時*
代表所有地址都允許。比如:
Access-Control-Allow-Headers:http://localhost:8081,http://localhost:8082
本方法是較為常用的一中跨域辦法,只需簡單修改服務端程式碼即可。
- 請求代理
這也是非常常用的一種跨域方法。跨域限制只是瀏覽器限制,服務端並沒有這個概念,因此我們在前端還是請求同域地址,然後在服務端做一個代理,將請求轉發到真正的 ip 和埠上。通常使用 nginx 實現埠轉發,比如下面一段 nginx 配置:
server {
# /test1/abc 轉發到 http://a.com:8011/abc
location /test1/ {
proxy_pass http://a.com:8011/;
}
# /test2/abc 轉發到 http://b.com:8011/main/abc
location /test2/ {
proxy_pass http://b.com:8011/main/;
}
# /test3/abc 轉發到 http://c.com:8011/test3/abc
location /test3/ {
proxy_pass http://c.com:8081;
}
}
cookie 同源策略
cookie 的同源策略是通過
Domain
和path
兩個部分來共同確認一個 cookie 在哪些頁面上可用。
Domain
確定這個 cookie 所屬的域名,不能帶埠或協議。因此 cookie 便可在不同埠/不同協議下共享,只要域名相同。有一個例外是父子域名間也能共享 cookie,只需將 Domain 設定為.父域名
。
path
就簡單多了,通過 Domain 確定哪些域名可以共享 cookie,然後在通過path
來確定 cookie 在哪些路徑下可用。使用/
表示所有路徑都可共享。
具體如下:
- Domain :
example
,path :/a
可獲取 cookie:http://example:8081/a,https://example:8081/a - Domain :
example
,path :/
可獲取 cookie:http://example:8081/a,https://example:8081/a , http://example:12/abcd - Domain :
.example
,path :/a
可獲取 cookie:http://example:8081/a , https://localhost:8081/a , http://test.example:889/a
注意:在跨域請求中,即時目標地址有 cookie 且發起請求的頁面也能讀取到該 cookie,瀏覽器也不會將 cookie 自動設定到該跨域請求中。比如在http://localhost:8082/a頁面中請求http://localhost:8081/abc,這兩個地址下擁有共享cookie,http請求也不會攜帶cookie。
本篇原創釋出於:FleyX 的個人部落格