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