<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 張精美動圖全面講解 CORS

          共 1938字,需瀏覽 4分鐘

           ·

          2020-10-29 12:11

          前言:

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

          覺得翻譯的不錯一定要點贊哦,謝謝你,這對我真的很重要!?

          注:原文的動圖均為 keynote 制作



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

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

          ??:這里原作者有個筆誤,把 https://api.mywebsite.com 誤寫為 https://www.mywebsite.com 了,圖中也有這個錯誤,讀者要注意一下不要被誤導

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

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

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

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

          1.同源策略

          瀏覽器網(wǎng)絡請求時,有一個同源策略的機制。即默認情況下,使用 API 的 Web 應用程序只能從加載應用程序的同一個域請求 HTTP 資源。

          比如說, https://www.mywebsite.com 請求 ?https://www.mywebsite.com/page 是完全沒有問題的。但是當資源位于不同協(xié)議、子域端口的站點時,這個請求就是跨域的。

          目前來看,同源策略會讓三種行為受限:

          • Cookie、LocalStorage 和 IndexDB 訪問受限
          • 無法操作跨域 DOM(常見于 iframe)
          • Javascript 發(fā)起的 XHR 和 Fetch 請求受限

          那么,為什么會存在同源策略呢?

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

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

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

          同源策略可以幫助我們解決這個安全問題,這個策略確保我們只能訪問同一站點的資源。

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

          說了這么多,同源策略和 CORS 又有什么關系?

          2.瀏覽器 CORS

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

          日常的業(yè)務開發(fā)中,我們會經(jīng)常訪問跨域資源,為了安全的請求跨域資源,瀏覽器使用一種稱為 CORS 的機制。

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

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

          Web 程序發(fā)出跨域請求后,瀏覽器會自動向我們的 HTTP header 添加一個額外的請求頭字段:Origin。Origin 標記了請求的站點來源:

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

          為了使瀏覽器允許訪問跨域資源, 服務器返回的 response 還需要加一些響應頭字段,這些字段將顯式表明此服務器是否允許這個跨域請求。

          3.服務端 CORS

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

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

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

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

          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???收到服務器返回的 response 后,瀏覽器中的 CORS 機制會檢查 Access-Control-Allow-Origin 的值是否等于 request 中 Origin 的值。

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

          3?? 瀏覽器校驗通過,前端成功地接收到跨域資源。


          那么,當我們試圖從一個沒有在 Access-Control-Allow-Origin 中列出的網(wǎng)站跨域訪問這些資源會發(fā)生什么呢?

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

          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。然而,服務器在 Access-Control-Allow-Origin 響應頭字段中沒有標記這個站點,瀏覽器 CORS 機制就阻止了這個響應,我們無法在我們的代碼中獲取響應數(shù)據(jù)。

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


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

          另一個常見的響應頭字段是 Access-Control-Allow-Methods。其指明了跨域請求所允許使用的 HTTP 方法。

          在上圖的案例中,只有GETPOSTPUT 方法被允許跨域訪問資源。其他 HTTP 方法,例如 PATCHDELETE 都會被阻止。

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

          說到PUT,PATCHDELETE 這幾個 HTTP 方法,CORS 處理這些方法時還有些不同。這些非簡單請求會觸發(fā) CORS 的預檢請求。

          4.預檢請求

          CORS 有兩種類型的請求:一種是簡單請求(simple request),一種是預檢請求(preflight request)。一個跨域請求到底是簡單的的還是預檢的,取決于一些 request header。

          當請求是 GETPOST 方法并且沒有任何自定義 Header 字段時,一般來說就是個簡單請求。除此之外的任何請求,諸如 PUTPATCHDELETE 方法,將會產(chǎn)生預檢。

          如果你想知道一個請求必須滿足哪些要求才能成為簡單請求,可以查看 MDN 簡單請求相關的文檔[5]。

          說了這么多,「預檢請求」到底是什么意思?下面我們就來探討一下。


          1???在發(fā)送實際請求之前,客戶端會先使用 `OPTIONS`[6] 方法發(fā)起一個預檢請求,預檢請求的 Access-Control-Request-* 中包含有關我們將要處理的實際請求的信息:

          • 首部字段 `Access-Control-Request-Method`[7] 告知服務器,實際請求要用到的方法是什么
          • 首部字段 `Access-Control-Request-Headers`[8] 告知服務器,實際請求將附帶的自定義請求首部字段是什么
          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???服務器接收到預檢請求后,會返回一個沒有 body 的 HTTP 響應,這個響應標記了服務器允許的 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?? 瀏覽器收到預檢響應,并檢查是否應允許發(fā)送實際請求。

          ??:上圖預檢響應漏了 Access-Control-Allow-Headers: Content-Type

          4?? 如果預檢響應檢測通過,瀏覽器會將實際請求發(fā)送到服務器,然后服務器返回我們需要的資源。

          如果預檢響應沒有檢驗通過,CORS 會阻止跨域訪問,實際的請求永遠不會被發(fā)送。預檢請求是一種很好的方式,可以防止我們訪問或修改那些沒有啟用 CORS 策略的服務器上的資源。

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

          5.認證

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

          盡管 CORS 默認情況下不發(fā)送身份憑證,但我們可以通過添加 Access-Control-Allow-Credentials CORS 響應頭來更改它。

          如果要在跨域請求中包含 cookie 和其他授權信息,我們需要做以下操作:

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

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

          //?服務器添加認證字段
          HTTP/1.1?200?OK
          Access-Control-Allow-Credentials:?true

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

          6.總結(jié)

          CORS Error 一定程度上會讓前端開發(fā)很頭疼,但是遵循它的相關規(guī)定后,它可以讓我們在瀏覽器中進行安全的跨域請求。

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

          7.最后

          這篇文章就到此結(jié)束了,如果覺得不錯的話一定要點贊鼓勵一下哦,祝大家學習進步,工作順利!

          如果想要學習更多非筆記式的 HTTP 知識,可以看看我之前寫的舊文:


          ??看完三件事

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

          1. 點贊,讓更多的人也能看到介紹內(nèi)容(收藏不點贊,都是耍流氓-_-)
          2. 關注公眾號“前端勸退師”,不定期分享原創(chuàng)知識。
          3. 也看看其他文章

          勸退師個人微信:huab119

          也可以來我的GitHub博客里拿所有文章的源文件:

          前端勸退指南:https://github.com/roger-hiro/BlogFN一起玩耍呀


          點贊、在看 支持作者??



          參考資料

          [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]

          好幾個 CORS 響應頭字段: 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 拿到的就是真實 IP 嗎?: https://juejin.im/post/6844904174132396045

          [13]

          HTTP 請求中,空格應該被編碼為 %20 還是 + ?: https://juejin.im/post/6844904178267979783



          瀏覽 55
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <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>
                  亚洲AV成人无码www在线观看 | 免费高清亚洲无码 | 9l视频自拍九色9l视频成人 | 免费超碰在线观看 | 日本视频,日本高清视频 |