當前位置:
首頁 > 知識 > 不要再問我跨域的問題了

不要再問我跨域的問題了

跨域這兩個字就像一塊狗皮膏藥一樣黏在每一個前端開發者身上,無論你在工作上或者面試中無可避免會遇到這個問題。為了應付面試,我每次都隨便背幾個方案,也不知道為什麼要這樣干,反正面完就可以扔了,我想工作上也不會用到那麼多亂七八糟的方案。到了真正工作,開發環境有 webpack-dev-server 搞定,上線了服務端的大佬們也會配好,配了什麼我不管,反正不會跨域就是了。日子也就這麼混過去了,終於有一天,我覺得不能再繼續這樣混下去了,我一定要徹底搞懂這個東西!於是就有了這篇文章。


要掌握跨域,首先要知道為什麼會有跨域這個問題出現

確實,我們這種搬磚工人就是為了混口飯吃嘛,好好的調個介面告訴我跨域了,這種阻礙我們輕鬆搬磚的事情真噁心!為什麼會跨域?是誰在搞事情?為了找到這個問題的始作俑者,請點擊瀏覽器的同源策略。 這麼官方的東西真難懂,沒關係,至少你知道了,因為瀏覽器的同源策略導致了跨域,就是瀏覽器在搞事情。 所以,瀏覽器為什麼要搞事情?就是不想給好日子我們過?對於這樣的質問,瀏覽器甩鍋道:「同源策略限制了從同一個源載入的文檔或腳本如何與來自另一個源的資源進行交互。這是一個用於隔離潛在惡意文件的重要安全機制。」 這麼官方的話術真難懂,沒關係,至少你知道了,似乎這是個安全機制。 所以,究竟為什麼需要這樣的安全機制?這樣的安全機制解決了什麼問題?別急,讓我們繼續研究下去。


沒有同源策略限制的兩大危險場景

據我了解,瀏覽器是從兩個方面去做這個同源策略的,一是針對介面的請求,二是針對 Dom 的查詢。試想一下沒有這樣的限制上述兩種動作有什麼危險。


沒有同源策略限制的介面請求

有一個小小的東西叫 cookie 大家應該知道,一般用來處理登錄等場景,目的是讓服務端知道誰發出的這次請求。如果你請求了介面進行登錄,服務端驗證通過後會在響應頭加入 Set-Cookie 欄位,然後下次再發請求的時候,瀏覽器會自動將 cookie 附加在 HTTP 請求的頭欄位 Cookie 中,服務端就能知道這個用戶已經登錄過了。知道這個之後,我們來看場景: 1. 你準備去清空你的購物車,於是打開了買買買網站 www.maimaimai.com,然後登錄成功,一看,購物車東西這麼少,不行,還得買多點。 2. 你在看有什麼東西買的過程中,你的好基友發給你一個鏈接 www.nidongde.com,一臉 yin 笑地跟你說:「你懂的」,你毫不猶豫打開了。 3. 你饒有興緻地瀏覽著 www.nidongde.com,誰知這個網站暗地裡做了些不可描述的事情!由於沒有同源策略的限制,它向 www.maimaimai.com 發起了請求!聰明的你一定想到上面的話 「服務端驗證通過後會在響應頭加入 Set-Cookie 欄位,然後下次再發請求的時候,瀏覽器會自動將 cookie 附加在 HTTP 請求的頭欄位 Cookie 中」,這樣一來,這個不法網站就相當於登錄了你的賬號,可以為所欲為了!如果這不是一個買買買賬號,而是你的銀行賬號,那…… 這就是傳說中的 CSRF 攻擊淺談 CSRF 攻擊方式。 看了這波 CSRF 攻擊我在想,即使有了同源策略限制,但 cookie 是明文的,還不是一樣能拿下來。於是我看了一些 cookie 相關的文章聊一聊 cookie、Cookie/Session 的機制與安全,知道了服務端可以設置 httpOnly,使得前端無法操作 cookie,如果沒有這樣的設置,像 XSS 攻擊就可以去獲取到 cookieWeb 安全測試之 XSS;設置 secure,則保證在 https 的加密通信中傳輸以防截獲。


沒有同源策略限制的 Dom 查詢

由此我們知道,同源策略確實能規避一些危險,不是說有了同源策略就安全,只是說同源策略是一種瀏覽器最基本的安全機制,畢竟能提高一點攻擊的成本。其實沒有刺不穿的盾,只是攻擊的成本和攻擊成功後獲得的利益成不成正比。

跨域正確的打開方式

經過對同源策略的了解,我們應該要消除對瀏覽器的誤解,同源策略是瀏覽器做的一件好事,是用來防禦來自邪門歪道的攻擊,但總不能為了不讓壞人進門而把全部人都拒之門外吧。沒錯,我們這種正人君子只要打開方式正確,就應該可以跨域。 下面將一個個演示正確打開方式,但在此之前,有些準備工作要做。為了本地演示跨域,我們需要: 1. 隨便跑起一份前端代碼(以下前端是隨便跑起來的 vue),地址是 http://localhost:9099。 2. 隨便跑起一份後端代碼(以下後端是隨便跑起來的 node koa2),地址是 http://localhost:9971。


同源策略限制下介面請求的正確打開方式

1.JSONP在 HTML 標籤里,一些標籤比如 script、img 這樣的獲取資源的標籤是沒有跨域限制的,利用這一點,我們可以這樣干:

後端寫個小介面

簡單版前端

簡單封裝一下前端這個套路

2. 空 iframe 加 form細心的朋友可能發現,JSONP 只能發 GET 請求,因為本質上 script 載入資源就是 GET,那麼如果要發 POST 請求怎麼辦呢?

後端寫個小介面

前端

3.CORS

CORS 是一個 W3C 標準,全稱是 "跨域資源共享"(Cross-origin resource sharing)跨域資源共享 CORS 詳解。看名字就知道這是處理跨域問題的標準做法。CORS 有兩種請求,簡單請求和非簡單請求。

這裡引用上面鏈接阮一峰老師的文章說明一下簡單請求和非簡單請求。 瀏覽器將 CORS 請求分成兩類:簡單請求(simple request)和非簡單請求(not-so-simple request)。

只要同時滿足以下兩大條件,就屬於簡單請求。 (1) 請求方法是以下三種方法之一:

HEAD

GET

POST

(2)HTTP 的頭信息不超出以下幾種欄位:

Accept

Accept-Language

Content-Language

Last-Event-ID

Content-Type:只限於三個值 application/x-www-form-urlencoded、multipart/form-data、text/plain

1. 簡單請求 後端

前端什麼也不用干,就是正常發請求就可以,如果需要帶 cookie 的話,前後端都要設置一下,下面那個非簡單請求例子會看到。

2. 非簡單請求 非簡單請求會發出一次預檢測請求,返回碼是 204,預檢測通過才會真正發出請求,這才返回 200。這裡通過前端發請求的時候增加一個額外的 headers 來觸發非簡單請求。

後端

一個介面就要寫這麼多代碼,如果想所有介面都統一處理,有什麼更優雅的方式呢?見下面的 koa2-cors。

前端

4. 代理想一下,如果我們請求的時候還是用前端的域名,然後有個東西幫我們把這個請求轉發到真正的後端域名上,不就避免跨域了嗎?這時候,Nginx 出場了。 Nginx 配置

前端就不用幹什麼事情了,除了寫介面,也沒後端什麼事情了

Nginx 轉發的方式似乎很方便!但這種使用也是看場景的,如果後端介面是一個公共的 API,比如一些公共服務獲取天氣什麼的,前端調用的時候總不能讓運維去配置一下 Nginx,如果兼容性沒問題(IE 10 或者以上),CROS 才是更通用的做法吧。

同源策略限制下 Dom 查詢的正確打開方式

1.postMessagewindow.postMessage() 是 HTML5 的一個介面,專註實現不同窗口不同頁面的跨域通訊。 為了演示方便,我們將 hosts 改一下:127.0.0.1 crossDomain.com,現在訪問域名 crossDomain.com 就等於訪問 127.0.0.1。

這裡是 http://localhost:9099/#/crossDomain,發消息方

這裡是 http://crossdomain.com:9099,接收消息方

結果可以看到:

3.canvas 操作圖片的跨域問題這個應該是一個比較冷門的跨域問題,張大神已經寫過了我就不再班門弄斧了解決 canvas 圖片 getImageData,toDataURL 跨域問題


最後

希望看完這篇文章之後,再有人問跨域的問題,你可以嘴角微微上揚,冷笑一聲:「不要再問我跨域的問題了。」 揚長而去。

作者:寫Bug

https://segmentfault.com/a/1190000015597029

---- 廣告----

給大家推薦個活躍的開發者社區:掘金是面向程序員的的技術社區,從大廠技術分享到前端開發最佳實踐,掃二維碼下載掘金APP,來掘金你不會錯過任何一個技術乾貨。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 JavaScript 的精彩文章:

用 npm script 打造超溜的前端工作流

TAG:JavaScript |