摘要:因?yàn)闉g覽器的同源策略,前端開發(fā)會(huì)遇到各種跨域問題。前言在總結(jié)各種跨域問題之前,我們先來(lái)了解一下瀏覽器的同源策略。所以只能解決一級(jí)域名相同二級(jí)域名不同的跨域問題。
跨域問題的場(chǎng)景和解決方案多種多樣,只要是做前端開發(fā),總會(huì)遇到。而且面試時(shí)也是必問的問題。所以自己學(xué)習(xí)總結(jié)記錄一下。
因?yàn)闉g覽器的同源策略,前端開發(fā)會(huì)遇到各種跨域問題。本篇文章總結(jié)了遇到跨域問題的不同的場(chǎng)景以及對(duì)應(yīng)的解決方案。
前言在總結(jié)各種跨域問題之前,我們先來(lái)了解一下瀏覽器的同源策略。
協(xié)議、域名、端口都相同才叫同源。具體的這里就不贅述了。
同源政策的目的,是為了保證用戶信息的安全,防止惡意的網(wǎng)站竊取數(shù)據(jù)。
設(shè)想這樣一種情況:A網(wǎng)站是一家銀行,用戶登錄以后,又去瀏覽其他網(wǎng)站。如果其他網(wǎng)站可以讀取A網(wǎng)站的 Cookie,會(huì)發(fā)生什么?
很顯然,如果 Cookie 包含隱私(比如存款總額),這些信息就會(huì)泄漏。更可怕的是,Cookie 往往用來(lái)保存用戶的登錄狀態(tài),如果用戶沒有退出登錄,其他網(wǎng)站就可以冒充用戶,為所欲為。因?yàn)闉g覽器同時(shí)還規(guī)定,提交表單不受同源政策的限制。
由此可見,"同源政策"是必需的,否則 Cookie 可以共享,互聯(lián)網(wǎng)就毫無(wú)安全可言了。
受到同源限制:
1)無(wú)法讀取不同源的 Cookie、LocalStorage 和 IndexDB 。
2)無(wú)法獲得不同源的DOM 。
3)不能向不同源的服務(wù)器發(fā)送ajax請(qǐng)求。
不受同源限制:
在瀏覽器中,、、、等標(biāo)簽都可以跨域加載資源,而不受同源策略的限制。
瀏覽器對(duì)跨域訪問的判定:
CORS機(jī)制把跨域請(qǐng)求分為兩類:簡(jiǎn)單請(qǐng)求和非簡(jiǎn)單請(qǐng)求。
1) 請(qǐng)求方法是以下三種方法之一:HEAD、GET、POST
2)HTTP的頭信息不超出以下幾種字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三個(gè)值application/x-www-form-urlencoded、multipart/form-data、text/plain
凡是不同時(shí)滿足上面兩個(gè)條件,就屬于非簡(jiǎn)單請(qǐng)求。瀏覽器對(duì)這兩種請(qǐng)求的處理,是不一樣的。
簡(jiǎn)單請(qǐng)求:瀏覽器會(huì)帶上Origin的請(qǐng)求頭發(fā)送到服務(wù)器,服務(wù)器根據(jù)Origin判斷是否許可。如果許可就會(huì)帶上CORS相關(guān)想要頭,如果不在許可范圍內(nèi)就不會(huì)帶上CORS相關(guān)的響應(yīng)頭。瀏覽器再根據(jù)響應(yīng)頭中是否有相關(guān)的CORS響應(yīng)頭,來(lái)判斷攔截響應(yīng)body和拋出錯(cuò)誤。
非簡(jiǎn)單請(qǐng)求:非簡(jiǎn)單請(qǐng)求會(huì)在發(fā)真正的請(qǐng)求之前發(fā)送一個(gè)OPTIONS的帶著Origin、Access-Control-Request-Method、Access-Control-Request-Headers等CORS相關(guān)的請(qǐng)求頭的預(yù)檢請(qǐng)求到服務(wù)器,服務(wù)器確認(rèn)可以這樣請(qǐng)求,就會(huì)返回帶著Access-Control-Allow-Origin、Access-Control-Allow-Methods、Access-Control-Allow-Headers等CORS相關(guān)的響應(yīng)頭的響應(yīng),瀏覽器檢查到相關(guān)的CORS響應(yīng)頭,說(shuō)明通過預(yù)檢可以繼續(xù)發(fā)送真正的請(qǐng)求;服務(wù)器確認(rèn)不可以,則不會(huì)返回這些相關(guān)響應(yīng)頭,瀏覽器沒檢查到CORS的響應(yīng)頭就會(huì)拋出錯(cuò)誤。
場(chǎng)景1:你的項(xiàng)目myweb,myweb的前端有一個(gè)接口是去訪問一個(gè)非myweb的服務(wù)器。非myweb服務(wù)器是第三方服務(wù)器,你不能去對(duì)第三方服務(wù)器做改動(dòng)。
場(chǎng)景2:你的項(xiàng)目是個(gè)微服務(wù)架構(gòu)的。那你的前端頁(yè)面可能就需要去很多個(gè)服務(wù)器上訪問數(shù)據(jù)。
原理解析:
跨域請(qǐng)求報(bào)錯(cuò)歸根結(jié)底是瀏覽器禁止使用XHR對(duì)象向不同源的服務(wù)器地址發(fā)起HTTP請(qǐng)求。如果是服務(wù)器跨域向多個(gè)不同的服務(wù)器發(fā)送請(qǐng)求就不會(huì)有跨域問題存在。因此,我們可以讓瀏覽器只向一個(gè)服務(wù)器方式請(qǐng)求,讓這個(gè)服務(wù)器代替瀏覽器去不同的服務(wù)器上請(qǐng)求資源再返回給瀏覽器。這個(gè)服務(wù)器就是代理服務(wù)器了。
下面推薦一個(gè)常用代理服務(wù)器nginx。
什么是nginx?
Nginx (engine x) 是一款輕量級(jí)的Web 服務(wù)器 、反向代理服務(wù)器及電子郵件(IMAP/POP3)代理服務(wù)器。
把ui所在的服務(wù)器和跨域服務(wù)器都用nginx代理轉(zhuǎn)發(fā),瀏覽器訪問nginx,nginx到ui服務(wù)獲取ui,再把ui下載到瀏覽器,瀏覽器發(fā)起ui中的URL,該URL為Nginx封裝后的跨域服務(wù)器的URL或ui服務(wù)器的URL,該URL到達(dá)Nginx之后,會(huì)被轉(zhuǎn)發(fā)到跨域服務(wù)器或ui服務(wù)器,請(qǐng)求處理完畢后,會(huì)通過Nginx中轉(zhuǎn)返回給瀏覽器。暴露出來(lái)的或者瀏覽器所發(fā)起的url都是nginx的url,nginx去跨域服務(wù)器和ui服務(wù)器獲取響應(yīng),返給瀏覽器,這樣就沒有跨域問題了。
二、CORS場(chǎng)景:
前后端分離的開發(fā)模式下,在本地進(jìn)行接口聯(lián)調(diào)時(shí):也許在你的項(xiàng)目里,你想嘗試前后端分離的開發(fā)模式。你在本地開發(fā)時(shí),mock了一些假數(shù)據(jù)來(lái)幫助自己本地開發(fā)。而有一天,你希望在本地和后端同學(xué)進(jìn)行聯(lián)調(diào)。此時(shí),后端rd的接口地址和你發(fā)生了跨域問題。這阻止了你們的聯(lián)調(diào),你只能繼續(xù)使用你mock的假數(shù)據(jù)。
解決方案:
CORS需要瀏覽器和服務(wù)器同時(shí)支持。如何支持?請(qǐng)看瀏覽器對(duì)跨域訪問的判定小節(jié)。
整個(gè)CORS通信過程,都是瀏覽器自動(dòng)完成,不需要用戶參與。對(duì)于開發(fā)者來(lái)說(shuō),CORS通信與同源的AJAX通信沒有差別,代碼完全一樣。瀏覽器一旦發(fā)現(xiàn)AJAX請(qǐng)求跨源,就會(huì)自動(dòng)添加一些附加的頭信息,有時(shí)還會(huì)多出一次附加的請(qǐng)求,但用戶不會(huì)有感覺。
因此,實(shí)現(xiàn)CORS通信的關(guān)鍵是服務(wù)器。只要服務(wù)器實(shí)現(xiàn)了CORS接口,就可以跨源通信。
服務(wù)器要給接口的響應(yīng)頭設(shè)置:Access-Control-Allow-Origin:*
場(chǎng)景:跨域發(fā)送get請(qǐng)求
jsonp解決跨域問題的本質(zhì):