3000字說說跨域!面試官聽完以後露出了滿意的笑容😎

2020年3月18日
《每日一題系列🚀》
做者:王二狗
博客:掘金思否知乎簡書CSDN
點贊再看,養成習慣,每日一題系列會一直更新下去,大家的支持是我持續分享的最大動力😘php

同源策略

在說跨域以前,首先須要瞭解的一個概念就是」同源策略「html

什麼是源?

源=協議+域名+端口號。ajax

若是兩個url的協議、域名、端口號徹底一致,那麼這兩個url就是同源的。json

咱們能夠經過window.originlocation.origin獲得當前源。segmentfault

https://wang.com
https://ergou.com
//不一樣源,域名不一致(記住:只有徹底如出一轍纔算同源)

http://wang.com/index.html
http://wang.com/server.php
//同源

localhost 調用 127.0.1 
//不一樣源
複製代碼

什麼是同源策略?

同源策略即:不一樣源之間的頁面,不許互相訪問數據。後端

瀏覽器規定:若是JS運行在源A裏,那麼就只能獲取源A的數據,不能獲取源B的數據,即不容許跨域。api

假設 wang.com/index.html引用了ergou.com/1.js,那麼就說1.js運行在源wang.com跨域

注意,這和ergou.com沒有關係,雖然1.js是從它那裏下載的.瀏覽器

因此1.js就只能獲取wang.com的數據,這就是瀏覽器的功能,瀏覽器就是故意這樣設計的。安全

爲何會有同源策略?

之因此須要使用同源策略,就是爲了保護用戶的隱私。

以微信爲例,源爲 https://user.weixin.com,假設當前用戶已經登陸,而且AJAX請求 /friends.json 能夠獲取用戶好友列表。

這個時候黑客來了,他把 https://user-winxin.com分享給你,實際上這是一個釣魚網站,你點開這個網頁,這個網頁也請求你的好友列表 https://user.weixin.com/friends.json。

請問,這個時候你的好友列表是否是就被黑客給偷走了?

問題的根源

之因此會出現這個問題,其根源就在於沒法區分發送者

微信裏面的JS和黑客的JS發送到請求幾乎沒有區別(referer區別)

可是若是後臺的開發者沒有檢查 referer,那麼就徹底沒有區別。

因此,若是沒有同源策略,任何頁面都能偷走微信裏面的數據,甚至是支付寶裏面的餘額。

安全原則

有的小夥伴可能會問,既然referer有區別,那檢查referer不就行了?

安全原則:安全鏈條上的強度取決於安全鏈條上最弱的一環。

同時,萬一這個網站的後端開發者是一個傻叉呢?

因此瀏覽器應該主動預防這種偷數據的行爲。

總之,爲了保護用戶的隱私,瀏覽器設置了嚴格的同源策略。

若是瀏覽器不限制跨域,必定是這個瀏覽器出現了bug

跨域

什麼是跨域?

跨域,即瀏覽器試圖執行其餘網站的腳本。可是因爲同源策略的限制,致使咱們沒法實現跨域。

關於跨域的幾個問題

爲何a.wang.com訪問wang.com也算跨域?

由於歷史上,出現過不一樣的公司共用域名,a.wang.comwang.com不必定是同一個網站,瀏覽器謹慎起見,認爲這是不一樣的源。

爲何不一樣端口也算跨域?

緣由同上,一個端口一個公司的狀況也不是沒有的。

記住:安全鏈條的強度取決於最弱的一環,全部和安全相關的問題都要謹慎對待。

爲何兩個網站的IP同樣,也算跨域?

緣由同上,由於IP也是能夠共用的。

爲何能夠跨域使用CSSJS和圖片等?

同源策略限制的是數據訪問,咱們引用CSSJS和圖片的時候,其實並不知道其內容,咱們只是在引用。

CORS跨域

什麼是CORS?

CORS的全稱是"跨域資源共享"(Cross-origin resource sharing)。 它容許瀏覽器向跨源服務器,發出XMLHttpRequest請求,從而克服了AJAX只能同源使用的限制。

如何理解CORS?

若是wang.comergou.com這兩個網站都是個人,我就是想讓wang.com去訪問ergou.com裏面的數據應該怎麼辦呢?

只須要wang.com在響應頭裏寫ergou.com能夠訪問便可。這就是CORS

實現CORS通訊的關鍵是服務器。只要服務器實現了CORS接口,就能夠跨源通訊。

兩種請求

CORS跨域分爲兩種請求,一種是簡單請求,另一種就是複雜請求

簡單請求

只要知足如下條件的就是簡單請求:

  • 請求方式爲HEADPOST 或者 GET
  • http頭信息不超出如下字段:AcceptAccept-LanguageContent-LanguageLast-Event-IDContent-Type(限於三個值:application/x-www-form-urlencodedmultipart/form-datatext/plain)

簡單請求的實現具體來講就是在信息頭中加入一個Origin字段:

GET /cors HTTP/1.1
Origin: http://wang.com
Host: api.ergou.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0
...
複製代碼

Origin的做用就是用來講明本次請求來自哪一個源,服務器會根據Origin的值來判斷是否接受本次請求。

若是Origin所表示的源不被服務器接受,即瀏覽器發現迴應的信息頭中沒有Access-Control-Allow-Origin字段,就會自動拋出一個錯誤。

注意:這種錯誤是沒法經過狀態碼識別的,這也是經過CORS實現跨域請求的一個弊端。

若是Origin所表示的源被服務器端所接受,那麼服務器就會返回以下響應:

Access-Control-Allow-Origin: http://api.ergou.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8
複製代碼
  • Access-Control-Allow-Origin :該字段是必須的。它的值要麼是請求時Origin字段的值,要麼是一個*,表示接受任意域名的請求
  • Access-Control-Allow-Credentials: 該字段可選。它的值是一個布爾值,表示是否容許發送Cookie。默認狀況下,Cookie不包括在CORS請求之中。設爲true,即表示服務器明確許可,Cookie能夠包含在請求中,一塊兒發給服務器。這個值也只能設爲true,若是服務器不要瀏覽器發送Cookie,刪除該字段便可。(注意:若是要發送cookie,不只要進行上述的設置,還要在AJAX請求中設置withCredentials屬性)
  • Access-Control-Expose-Headers:該字段可選。CORS請求時,XMLHttpRequest對象的getResponseHeader()方法只能拿到6個基本字段:Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma。若是想拿到其餘字段,就必須在Access-Control-Expose-Headers裏面指定。

複雜請求

所謂複雜請求,即不知足上述條件的請求就是複雜請求。

好比請求的方法是PUTDELETE,或者Content-Type字段的類型是application/json

複雜請求首先會發起一個預檢請求,該請求是 option 方法的,經過該請求來知道服務端是否容許跨域請求。

var url = 'http://api.wang.com/cors';
var xhr = new XMLHttpRequest();
xhr.open('PUT', url, true);
xhr.setRequestHeader('X-Custom-Header', 'value');
xhr.send();
複製代碼

上面的請求就是一個複雜請求,當瀏覽器發現這是一個複雜請求以後,就會主動發出一個預檢請求,詢問服務器是否容許本次請求。

服務器收到預檢請求以後,檢查了OriginAccess-Control-Request-MethodAccess-Control-Request-Headers字段之後,確認容許跨源請求,纔會作出相應的迴應。

Access-Control-Allow-Origin: http://api.wang.com
Content-Type: text/html; charset=utf-8
複製代碼

CORS存在的問題

不支持IE8/9,若是要在IE8/9使用CORS跨域須要使用XDomainRequest對象來支持CORS

JSONP跨域

什麼是JSONP?

咱們在跨域的時候因爲當前的瀏覽器不支持 CORS 或者由於某些條件不支持 CORS,咱們必須使用另一種方式來跨域,因而咱們就請求一個 JS 文件,這個 JS 文件會執行一個回調,回調裏面就有咱們須要的數據。

let script = document.createElement('script');

script.src = 'http://www.wang.cn/login?username=wang&callback=callback';

document.body.appendChild(script);

function callback(res) {
  console.log(res);
}

複製代碼

回調函數的名字是什麼?

回調的名字是能夠隨機生成的的一個隨機數,咱們把這個名字當成 callback 的參數傳給後臺,後臺會把這個函數再次返回給咱們並執行

JSONP跨域優勢

  • 兼容ie
  • 能夠跨域

JSONP跨域缺點

  • 因爲是 script 標籤,因此讀不到 ajax 那麼精確的狀態,不知道狀態碼是什麼,也不知道響應頭是什麼,它只知道成功和失敗。
  • 不支持post(由於是 script 標籤,因此只支持 get 請求)

告誡本身,即便再累也不要忘記學習,成功沒有捷徑可走,只有一步接着一步走下去。 共勉!

文章中若有不對的地方,歡迎小夥伴們多多指正。

謝謝你們~ 💘

相關文章
相關標籤/搜索