1.跨域問題的由來
何謂同源:URL由協定、域名、端口和路徑組成,如果兩個URL的協定、域名和端口相同,則表示它們同源。浏覽器的同源政策,從一個域上加載的腳本不允許通路另外一個域的文檔屬性 ,是浏覽器上為安全性考慮實施的非常重要的安全政策。舉個例子:比如一個惡意網站的頁面通過iframe嵌入了銀行的登入頁面(二者不同源),如果沒有同源限制,惡意網頁上的javascript腳本就可以在使用者登入銀行的時候擷取使用者名和密碼。
2.跨域的影響範圍
在浏覽器中,<script>、<img>、<iframe>、<link>等标簽都可以加載跨域資源,而不受同源限制,
但浏覽器會限制腳本中發起的跨域請求。比如,使用 XMLHttpRequest 對象和Fetch發起 HTTP 請求就必須遵守同源政策。
Web 應用程式通過 XMLHttpRequest 對象或Fetch能且隻能向同域名的資源發起 HTTP 請求,而不能向任何其它域名發起請求。
不允許跨域通路并非是浏覽器限制了發起跨站請求,而是跨站請求可以正常發起,但是傳回結果被浏覽器攔截了。
最好的例子是CSRF跨站攻擊原理,請求是發送到了後端伺服器,無論是否設定允許跨域,
有些浏覽器不允許從HTTPS跨域通路HTTP,比如Chrome和Firefox,這些浏覽器在請求還未發出的時候就會攔截請求,這是特例。
此外父頁面js操作不同域的iframe屬性時,也會受到跨域限制
3.跨域方法
克服跨域限制的方法有(實踐中後兩種最常用,是以重點介紹):
(1)通過jsonp跨域
(2)通過修改document.domain來跨子域
(3)使用window.name來進行跨域
(4)使用HTML5中新引進的window.postMessage方法來跨域傳送資料
(5)使用代理伺服器,使用代理方式跨域更加直接,因為同源限制是浏覽器實作的。如果請求不是從浏覽器發起的,就不存在跨域問題了。
使用這個方法跨域步驟如下:
1. 把通路其它域的請求替換為本域的請求
2. 伺服器端的動态腳本負責将本域的請求轉發成實際的請求
為了通過Ajax從http://localhost:8080通路http://localhost:8081/api,可以将請求發往http://localhost:8080/api。
然後利用Apache Web/Nginx 伺服器的Reverse Proxy功能做如下配置:ProxyPass /api http://localhost:8081/api
(6)CORS全稱是"跨域資源共享"(Cross-origin resource sharing),CORS需要浏覽器和伺服器同時支援。目前,所有浏覽器都支援該功能
(IE浏覽器不能低于IE10),是以,實作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
凡是不同時滿足上面兩個條件,就屬于非簡單請求。
對于簡單請求,浏覽器在發出CORS請求時會在頭資訊之中增加一個Origin字段。伺服器的傳回會多出3個字段:
Access-Control-Allow-Origin(必須) 允許跨域的源
Access-Control-Allow-Credentials(可選) 表示是否允許發送Cookie。預設情況下,Cookie可以包含在請求中,一起發給伺服器
如果伺服器不需要浏覽器發送Cookie,删除該字段即可。
Access-Control-Expose-Headers(可選) CORS請求時,XMLHttpRequest對象的getResponseHeader()方法隻能拿到6個基本字段:
Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,
就必須在Access-Control-Expose-Headers裡面指定。如指定Access-Control-Expose-Headers: FooBar,則可通過
getResponseHeader('FooBar')擷取FooBar字段的值。
非簡單請求是那種對伺服器有特殊要求的請求,比如請求方法是PUT或DELETE,或者Content-Type字段的類型是application/json。
非簡單請求的CORS請求,會在正式通信之前,增加一次HTTP查詢請求,稱為"預檢"請求(preflight)。
"預檢"請求用的請求方法是OPTIONS,表示這個請求是用來詢問的。頭資訊裡面,關鍵字段是Origin,表示請求來自哪個源。
浏覽器先詢問伺服器,目前網頁所在的域名是否在伺服器的許可名單之中,以及可以使用哪些HTTP動詞和頭資訊字段。隻有得到肯定答複,
浏覽器才會發出正式的XMLHttpRequest請求,否則就報錯。