<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          驚艷!15 張精美動(dòng)圖全面演示 CORS 過(guò)程!

          共 1938字,需瀏覽 4分鐘

           ·

          2020-10-20 01:56

          前言:

          本文翻譯自 Lydia Hallie[1] 小姐姐寫(xiě)的 ??? CS Visualized: CORS[2],她用了大量的動(dòng)圖去解釋 CORS 這個(gè)概念,國(guó)內(nèi)還沒(méi)有人翻譯本文,所以我在原文的理解上翻譯了本文并修改了一些錯(cuò)誤,希望能幫到大家。

          覺(jué)得翻譯的不錯(cuò)一定要點(diǎn)贊哦,謝謝你,這對(duì)我真的很重要!?

          注:原文的動(dòng)圖均為 keynote 制作



          前端開(kāi)發(fā)中,我們經(jīng)常要使用其他站點(diǎn)的數(shù)據(jù)。前端顯示這些數(shù)據(jù)之前,必須向服務(wù)器發(fā)出請(qǐng)求以獲取該數(shù)據(jù)。

          假設(shè)我們正在訪(fǎng)問(wèn) https://api.mywebsite.com 這個(gè)站點(diǎn),點(diǎn)擊按鈕向 ?https://api.mywebsite.com/users 發(fā)送請(qǐng)求,獲取網(wǎng)站上的一些用戶(hù)信息:

          ??:這里原作者有個(gè)筆誤,把 https://api.mywebsite.com 誤寫(xiě)為 https://www.mywebsite.com 了,圖中也有這個(gè)錯(cuò)誤,讀者要注意一下不要被誤導(dǎo)

          從結(jié)果上看表現(xiàn)非常完美,我們向服務(wù)器發(fā)送請(qǐng)求,服務(wù)器返回了我們需要的 JSON 數(shù)據(jù),前端也正常的渲染出了結(jié)果。

          下面我們換一個(gè)網(wǎng)站試試。用 ?https://www.anotherwebsite.com 這個(gè)網(wǎng)站向 https://api.website.com/users 發(fā)送請(qǐng)求:

          問(wèn)題來(lái)了,我們請(qǐng)求同樣的接口網(wǎng)站,但是這次瀏覽器給我們拋出一個(gè) Error。

          剛剛瀏覽器拋出的就是 CORS Error,下面讓我們分析一下為什么會(huì)產(chǎn)生這種 Error,以及這個(gè) Error 的確切含義是什么。

          1.同源策略

          瀏覽器網(wǎng)絡(luò)請(qǐng)求時(shí),有一個(gè)同源策略的機(jī)制。即默認(rèn)情況下,使用 API 的 Web 應(yīng)用程序只能從加載應(yīng)用程序的同一個(gè)域請(qǐng)求 HTTP 資源。

          比如說(shuō), https://www.mywebsite.com 請(qǐng)求 ?https://www.mywebsite.com/page 是完全沒(méi)有問(wèn)題的。但是當(dāng)資源位于不同協(xié)議子域端口的站點(diǎn)時(shí),這個(gè)請(qǐng)求就是跨域的。

          目前來(lái)看,同源策略會(huì)讓三種行為受限:

          • Cookie、LocalStorage 和 IndexDB 訪(fǎng)問(wèn)受限
          • 無(wú)法操作跨域 DOM(常見(jiàn)于 iframe)
          • Javascript 發(fā)起的 XHR 和 Fetch 請(qǐng)求受限

          那么,為什么會(huì)存在同源策略呢?

          我們做個(gè)假設(shè),如果不存在同源策略,你無(wú)意中點(diǎn)擊了七大姑在微信上給你發(fā)的一篇養(yǎng)生文章鏈接。其實(shí)這個(gè)網(wǎng)頁(yè)是個(gè)釣魚(yú)網(wǎng)站,訪(fǎng)問(wèn)鏈接后就把你重定向到一個(gè)嵌入了 iframe 的攻擊網(wǎng)站,這個(gè) iframe 會(huì)自動(dòng)加載銀行網(wǎng)站,并通過(guò) cookies 登錄你的賬戶(hù)。

          登陸成功后,這個(gè)釣魚(yú)網(wǎng)站還可以控制 iframe 的 DOM,通過(guò)一系列騷操作把你卡里的錢(qián)轉(zhuǎn)走。

          這是一個(gè)非常嚴(yán)重的安全漏洞,我們不希望自己在互聯(lián)網(wǎng)的內(nèi)容被隨便訪(fǎng)問(wèn),更不要說(shuō)這種涉及到錢(qián)的網(wǎng)站了。

          同源策略可以幫助我們解決這個(gè)安全問(wèn)題,這個(gè)策略確保我們只能訪(fǎng)問(wèn)同一站點(diǎn)的資源。

          在這種情況下,https://www.evilwebsite.com 嘗試跨站訪(fǎng)問(wèn) https://www.bank.com 的資源,同源策略就會(huì)阻止這個(gè)操作,讓釣魚(yú)網(wǎng)站無(wú)法訪(fǎng)問(wèn)銀行網(wǎng)站的數(shù)據(jù)。

          說(shuō)了這么多,同源策略和 CORS 又有什么關(guān)系?

          2.瀏覽器 CORS

          出于安全原因,瀏覽器限制從腳本內(nèi)發(fā)起的跨域 HTTP 請(qǐng)求。例如 XHR 和 Fetch 就遵循同源策略。這意味著使用 API 的 Web 應(yīng)用程序只能從加載應(yīng)用程序的同一個(gè)域請(qǐng)求 HTTP 資源。

          日常的業(yè)務(wù)開(kāi)發(fā)中,我們會(huì)經(jīng)常訪(fǎng)問(wèn)跨域資源,為了安全的請(qǐng)求跨域資源,瀏覽器使用一種稱(chēng)為 CORS 的機(jī)制。

          CORS 的全名是 Cross-Origin Resource Sharing,即跨域資源共享。盡管默認(rèn)情況下瀏覽器禁止我們?cè)L問(wèn)跨域資源,但是我們可以利用 CORS 放寬這種限制,在保證安全性的前提下訪(fǎng)問(wèn)跨域資源。

          瀏覽器可以利用 CORS 機(jī)制,放行符合規(guī)范的跨域訪(fǎng)問(wèn),阻止不合規(guī)范的跨域訪(fǎng)問(wèn)。瀏覽器內(nèi)部是怎么做的呢?我們下面就來(lái)分析一下。

          Web 程序發(fā)出跨域請(qǐng)求后,瀏覽器會(huì)自動(dòng)向我們的 HTTP header 添加一個(gè)額外的請(qǐng)求頭字段:OriginOrigin 標(biāo)記了請(qǐng)求的站點(diǎn)來(lái)源:

          GET https://api.website.com/users HTTP/1/1
          Origin: https://www.mywebsite.com // <- 瀏覽器自己加的

          為了使瀏覽器允許訪(fǎng)問(wèn)跨域資源, 服務(wù)器返回的 response 還需要加一些響應(yīng)頭字段,這些字段將顯式表明此服務(wù)器是否允許這個(gè)跨域請(qǐng)求。

          3.服務(wù)端 CORS

          作為服務(wù)器開(kāi)發(fā)人員,我們可以通過(guò)在 HTTP 響應(yīng)中添加額外的響應(yīng)頭字段 Access-Control-* 來(lái)表明是否允許跨域請(qǐng)求。根據(jù)這些 CORS 響應(yīng)頭字段,瀏覽器可以允許一些被同源策略限制的跨源響應(yīng)。

          雖然有好幾個(gè) CORS 響應(yīng)頭字段[3],但有一個(gè)字段是必加的,那就是 Access-Control-Allow-Origin。這個(gè)頭字段的值指定了哪些站點(diǎn)被允許跨域訪(fǎng)問(wèn)資源。

          1?? 如果我們有服務(wù)器的開(kāi)發(fā)權(quán)限,我們可以給 https://www.mywebsite.com 加上訪(fǎng)問(wèn)權(quán)限:將該域添加到 Access-Control-Allow-Origin 中。

          這個(gè)響應(yīng)頭字段現(xiàn)在被添加到服務(wù)器發(fā)回給客戶(hù)端的 response header 中。這個(gè)字段添加后,如果我們從 https://www.mywebsite.com 發(fā)送跨域請(qǐng)求,同源策略將不再限制 https://api.mywebsite.com 站點(diǎn)返回的資源。

          HTTP/1.1 200 OK
          Access-Control-Allow-Origin: https://www.mywebsite.com
          Date: Fri, 11 Oct 2019 15:47 GM
          Content-Length: 29
          Content-Type: application/json
          Server: Apache

          {user: [{...}]}

          2???收到服務(wù)器返回的 response 后,瀏覽器中的 CORS 機(jī)制會(huì)檢查 Access-Control-Allow-Origin 的值是否等于 request 中 Origin 的值。

          在這個(gè)例子中,request 的 Originhttps://www.mywebsite.com,這和 response 中 Access-Control-Allow-Origin 的值是一樣的:

          3?? 瀏覽器校驗(yàn)通過(guò),前端成功地接收到跨域資源。


          那么,當(dāng)我們?cè)噲D從一個(gè)沒(méi)有在 Access-Control-Allow-Origin 中列出的網(wǎng)站跨域訪(fǎng)問(wèn)這些資源會(huì)發(fā)生什么呢?

          如上圖所示,從 https://www.anotherwebsite.com 跨域訪(fǎng)問(wèn) https://api.mywebsite.com 資源,瀏覽器拋出一個(gè) CORS Error,經(jīng)過(guò)上面的講解,我們可以讀懂這個(gè)報(bào)錯(cuò)信息了:

          The?'Access-Control-Allow-Origin'?header?has?a?value
          ?'https://www.mywebsite.com'?that?is?not?equal?
          to?the?supplied?origin.?

          在這種情況下,Origin 的值是 https://www.anotherwebsite.com。然而,服務(wù)器在 Access-Control-Allow-Origin 響應(yīng)頭字段中沒(méi)有標(biāo)記這個(gè)站點(diǎn),瀏覽器 CORS 機(jī)制就阻止了這個(gè)響應(yīng),我們無(wú)法在我們的代碼中獲取響應(yīng)數(shù)據(jù)。

          CORS 還允許我們添加通配符 * 作為允許的外域,這意味著該資源可以被任意外域訪(fǎng)問(wèn),所以要注意這種特殊情況


          Access-Control-Allow-Origin 是 CORS 機(jī)制提供的眾多頭字段之一。服務(wù)器開(kāi)發(fā)人員還可以通過(guò)其它頭字段擴(kuò)展服務(wù)器的 CORS 策略,以允許/禁止某些請(qǐng)求。

          另一個(gè)常見(jiàn)的響應(yīng)頭字段是 Access-Control-Allow-Methods。其指明了跨域請(qǐng)求所允許使用的 HTTP 方法。

          在上圖的案例中,只有GETPOSTPUT 方法被允許跨域訪(fǎng)問(wèn)資源。其他 HTTP 方法,例如 PATCHDELETE 都會(huì)被阻止。

          如果您想知道其它的 CORS 響應(yīng)頭字段是什么以及它們的用途,可以查看此列表[4]

          說(shuō)到PUTPATCHDELETE 這幾個(gè) HTTP 方法,CORS 處理這些方法時(shí)還有些不同。這些非簡(jiǎn)單請(qǐng)求會(huì)觸發(fā) CORS 的預(yù)檢請(qǐng)求。

          4.預(yù)檢請(qǐng)求

          CORS 有兩種類(lèi)型的請(qǐng)求:一種是簡(jiǎn)單請(qǐng)求(simple request),一種是預(yù)檢請(qǐng)求(preflight request)。一個(gè)跨域請(qǐng)求到底是簡(jiǎn)單的的還是預(yù)檢的,取決于一些 request header。

          當(dāng)請(qǐng)求是 GETPOST 方法并且沒(méi)有任何自定義 Header 字段時(shí),一般來(lái)說(shuō)就是個(gè)簡(jiǎn)單請(qǐng)求。除此之外的任何請(qǐng)求,諸如 PUTPATCHDELETE 方法,將會(huì)產(chǎn)生預(yù)檢。

          如果你想知道一個(gè)請(qǐng)求必須滿(mǎn)足哪些要求才能成為簡(jiǎn)單請(qǐng)求,可以查看 MDN 簡(jiǎn)單請(qǐng)求相關(guān)的文檔[5]

          說(shuō)了這么多,「預(yù)檢請(qǐng)求」到底是什么意思?下面我們就來(lái)探討一下。


          1???在發(fā)送實(shí)際請(qǐng)求之前,客戶(hù)端會(huì)先使用 `OPTIONS`[6] 方法發(fā)起一個(gè)預(yù)檢請(qǐng)求,預(yù)檢請(qǐng)求的 Access-Control-Request-* 中包含有關(guān)我們將要處理的實(shí)際請(qǐng)求的信息:

          • 首部字段 `Access-Control-Request-Method`[7] 告知服務(wù)器,實(shí)際請(qǐng)求要用到的方法是什么
          • 首部字段 `Access-Control-Request-Headers`[8] 告知服務(wù)器,實(shí)際請(qǐng)求將附帶的自定義請(qǐng)求首部字段是什么
          OPTIONS https://api.mywebsite.com/user/1 HTTP/1.1
          Origin: https://www.mywebsite.com
          Access-Control-Request-Method: PUT
          Access-Control-Request-Headers: Content-Type

          2???服務(wù)器接收到預(yù)檢請(qǐng)求后,會(huì)返回一個(gè)沒(méi)有 body 的 HTTP 響應(yīng),這個(gè)響應(yīng)標(biāo)記了服務(wù)器允許的 HTTP 方法和 HTTP Header 字段:

          HTTP/1.1 204 No Content
          Access-Control-Allow-Origin: https://www.mywebsite.com
          Access-Control-Request-Method: GET POST PUT
          Access-Control-Request-Headers: Content-Type

          3?? 瀏覽器收到預(yù)檢響應(yīng),并檢查是否應(yīng)允許發(fā)送實(shí)際請(qǐng)求。

          ??:上圖預(yù)檢響應(yīng)漏了 Access-Control-Allow-Headers: Content-Type

          4?? 如果預(yù)檢響應(yīng)檢測(cè)通過(guò),瀏覽器會(huì)將實(shí)際請(qǐng)求發(fā)送到服務(wù)器,然后服務(wù)器返回我們需要的資源。

          如果預(yù)檢響應(yīng)沒(méi)有檢驗(yàn)通過(guò),CORS 會(huì)阻止跨域訪(fǎng)問(wèn),實(shí)際的請(qǐng)求永遠(yuǎn)不會(huì)被發(fā)送。預(yù)檢請(qǐng)求是一種很好的方式,可以防止我們?cè)L問(wèn)或修改那些沒(méi)有啟用 CORS 策略的服務(wù)器上的資源。

          ? 為了減少網(wǎng)絡(luò)往返次數(shù),我們可以通過(guò)在 CORS 請(qǐng)求中添加 ?Access-Control-Max-Age 頭字段來(lái)緩存預(yù)檢響應(yīng)。瀏覽器可以使用緩存來(lái)代替發(fā)送新的預(yù)檢請(qǐng)求。

          5.認(rèn)證

          XHR 或 Fetch 與 CORS 的一個(gè)有趣的特性是,我們可以基于 Cookies[9] 和 HTTP 認(rèn)證信息發(fā)送身份憑證。一般而言,對(duì)于跨域 XHR 或 Fetch 請(qǐng)求,瀏覽器不會(huì)發(fā)送身份憑證信息。

          盡管 CORS 默認(rèn)情況下不發(fā)送身份憑證,但我們可以通過(guò)添加 Access-Control-Allow-Credentials CORS 響應(yīng)頭來(lái)更改它。

          如果要在跨域請(qǐng)求中包含 cookie 和其他授權(quán)信息,我們需要做以下操作:

          • XHR 請(qǐng)求中將 withCredentials 字段設(shè)置為 true
          • Fetch 請(qǐng)求中將 credentials 設(shè)為 include
          • 服務(wù)器把 Access-Control-Allow-Credentials: true 添加到響應(yīng)頭中
          //?瀏覽器?fetch?請(qǐng)求
          fetch('https://api.mywebsite,com.users',?{
          ??credentials:?"include"
          })

          //?瀏覽器?XHR?請(qǐng)求
          let?xhr?=?new?XMLHttpRequest();
          xhr.withCredentials?=?true;

          //?服務(wù)器添加認(rèn)證字段
          HTTP/1.1?200?OK
          Access-Control-Allow-Credentials:?true

          把上面的工作做好后,我們就可以在跨域請(qǐng)求中包含身份憑證信息了。

          6.總結(jié)

          CORS Error 一定程度上會(huì)讓前端開(kāi)發(fā)很頭疼,但是遵循它的相關(guān)規(guī)定后,它可以讓我們?cè)跒g覽器中進(jìn)行安全的跨域請(qǐng)求。

          同源策略和 CORS 的知識(shí)點(diǎn)有很多,本文只講了一些關(guān)鍵知識(shí)點(diǎn),如果你想全面學(xué)習(xí) CORS 的相關(guān)知識(shí),我推薦你查閱MDN 文檔[10]W3C 規(guī)范[11],這些一手知識(shí)是最準(zhǔn)確的。

          7.最后

          這篇文章就到此結(jié)束了,如果覺(jué)得不錯(cuò)的話(huà)一定要點(diǎn)贊鼓勵(lì)一下哦,祝大家學(xué)習(xí)進(jìn)步,工作順利!

          如果想要學(xué)習(xí)更多非筆記式的 HTTP 知識(shí),可以看看我之前寫(xiě)的舊文:


          參考資料

          [1]

          Lydia Hallie: https://dev.to/lydiahallie

          [2]

          ??? CS Visualized: CORS: https://dev.to/lydiahallie/cs-visualized-cors-5b8h?utm_campaign=React%2BNative%2BNow&utm_medium=web&utm_source=React_Native_Now_69#cs-cors

          [3]

          好幾個(gè) CORS 響應(yīng)頭字段: https://fetch.spec.whatwg.org/#http-responses

          [4]

          查看此列表: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#The_HTTP_response_headers

          [5]

          文檔: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Simple_requests

          [6]

          OPTIONS: https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Methods/OPTIONS

          [7]

          Access-Control-Request-Method: https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Access-Control-Request-Method

          [8]

          Access-Control-Request-Headers: https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Access-Control-Request-Headers

          [9]

          Cookies: https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies

          [10]

          MDN 文檔: https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS

          [11]

          W3C 規(guī)范: https://www.w3.org/wiki/CORS_Enabled

          [12]

          X-Forwarded-For 拿到的就是真實(shí) IP 嗎?: https://juejin.im/post/6844904174132396045

          [13]

          HTTP 請(qǐng)求中,空格應(yīng)該被編碼為 %20 還是 + ?: https://juejin.im/post/6844904178267979783


          最后



          如果你覺(jué)得這篇內(nèi)容對(duì)你挺有啟發(fā),我想邀請(qǐng)你幫我三個(gè)小忙:

          1. 點(diǎn)個(gè)「在看」,讓更多的人也能看到這篇內(nèi)容(喜歡不點(diǎn)在看,都是耍流氓 -_-)

          2. 歡迎加我微信「qianyu443033099」拉你進(jìn)技術(shù)群,長(zhǎng)期交流學(xué)習(xí)...

          3. 關(guān)注公眾號(hào)「前端下午茶」,持續(xù)為你推送精選好文,也可以加我為好友,隨時(shí)聊騷。


          點(diǎn)個(gè)在看支持我吧,轉(zhuǎn)發(fā)就更好了


          瀏覽 55
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  www.亚洲天堂 | 懂色av蜜桃av | 婷婷五月天小说亚洲 | 国产激情无码免费 | 五级 黄 色 片 |