CORS全稱「跨站資源共享」(Cross-Origin Resource Sharing),它容許瀏覽器克服瀏覽器同源策略向跨域服務器發出請求。html
說到CORS,那麼就不得不提瀏覽器同源策略,所謂「同源」,是指服務器URL的三個相同:web
1.協議相同json
2.域名相同跨域
3.端口相同瀏覽器
舉個栗子:好比一個URL是http://www.example.com:80/a.html
,那麼:緩存
http://www.example.com:80/b.html // 同源 https://www.example.com:80/a.html // 非同源(協議不一樣) http://www.example1.com:80/a.html // 非同源(域名不一樣) http://www.example.com:81/a.html // 非同源(端口不一樣)
若是非同源,那麼三種行爲將受到限制:安全
1.非同源頁面沒法跨域讀取瀏覽器本地數據存儲(Cookie、LocalStorage和IndexDB)服務器
2.非同源頁面沒法跨域獲取DOMwebsocket
3.非同源頁面沒法跨域發送AJAX請求app
那麼,爲何瀏覽器要使用同源策略?
同源策略的目的,是爲了保證用戶的信息安全,防止被不法分子竊取數據。而衆所周知,Cookie包含大量的登陸信息,若是一個網頁能夠跨域訪問另外一個網站的Cookie,那麼不法分子能夠經過使用跨域訪問獲取Cookie而後冒充用戶,隨心所欲。
因而可知,同源策略是極其有必要的。
可是,不少時候,咱們須要跨域發送AJAX請求,此時咱們就須要突破同源策略不容許發送跨域AJAX的規定。隨着技術的發展,有不少技術能夠實現跨域發送AJAX請求,常見的有如下三種:
1.JSONP
2.Websocket
3.CORS
JSONP是CORS技術出來以前最經常使用的跨域解決方案,最大的特定是兼容性好,簡單,不須要進行大的服務器改動。它的基本思路是經過動態添加一個script標籤,向服務器請求腳本,腳本中通常調用一個客戶端定義的函數,將數據做爲參數,調用客戶端的函數,而客戶端經過操做該函數,可使用被當作參數傳過來的數據。
由於服務器不限制script的跨域,因此不受跨域影響。
衆所周知,Websocket是一個持久化協議,經常使用於解決服務器推送問題。可是,實際上Websocket其實支持跨域通訊。經過設置Websocket的origin
的字段,能夠規定容許跨域的站點。
上面兩種方法雖然能夠解決跨域,可是,都有着各類問題。
慶幸的是,本文的主角:CORS的出現,完全解決了跨域問題。
瀏覽器將跨域AJAX請求分爲兩類:簡單請求和非簡單請求,對應有兩種不一樣的處理方式。
何爲簡單請求?
簡單請求就是知足如下兩個條件的請求:
1.請求方法爲HEAD、GET和POST
2.HTTP請求頭只包含:Accept
、Accept-Language
、Content-Language
、Last-Event-ID
以及值爲application/x-www-form-urlencoded
、multipart/form-data
、text/plain
三者之一的Content-Type
對於簡單請求,瀏覽器能夠直接發送請求到服務器,可是會在請求頭中添加一個origin
字段,該字段用來講明請求的來源。服務器會識別該字段,判斷是否容許跨域。
若是容許跨域,服務器會返回結果並在響應頭上添加三個字段:
1.Access-Control-Allow-Origin
該字段的值爲Origin字段的值,或者是*
,表示服務器接受任何源的跨域請求。
2.Access-Control-Allow-Credentials
可選字段,它表示是否容許發送Cookie,值爲true
時,表示發送請求的時候容許發送Cookie,若是不包含該字段,則表示不容許發送Cookie。
值得一提的是,若是服務器容許發送Cookie,那麼不容許將Access-Control-Allow-Origin
的值設爲*
。
3.Access-Control-Expose-Headers
可選字段,在沒有該字段的狀況下,針對跨域請求,XHR對象的getResponseHeader()
方法只能拿到Cache-Control
、Content-Language
、Content-Type
、Expire
、Last-Modified
、Pragma
這六個字段,該字段能夠設置額外能夠拿到的字段。
不知足簡單請求的跨域請求都是非簡單請求,好比PUT或DELETE方法。
不一樣於簡單請求的直接向服務器請求,非簡單請求會在發送以前,先進行一次「預檢」(preflight),即,向服務器發出一個OPTIONS請求,查詢服務器是否容許它進行跨域請求。
若是服務器不經過「預檢」,會返回一個error,客戶端能夠經過onerror事件進行捕獲。
當服務器經過「預檢」後,服務器會進行響應,響應頭中含有CORS的相關字段,分別是:
1.Access-Control-Allow-Origin
該字段和簡單請求中的同名字段同樣。
2.Access-Control-Allow-Methods
該字段表示服務器支持跨域的全部方法,是一個逗號分隔的字符串,如:POST,DELETE。
3.Access-Control-Allow-Headers
該字段表示服務器支持的全部頭信息,也是一個逗號分隔的字符串。
4.Access-Control-Allow-Credentials
可選字段,與簡單請求中的同名字段同樣。
5.Access-Control-Max-Age
可選字段,在一段時間內,瀏覽器對同一個域名進行非簡單跨域請求,只對第一次進行「預檢」,而這一次「預檢」的結果將被緩存,接下來的請求都經過該結果進行判斷。該字段就是用來設置「預檢」結果緩存的時間長短,能夠將其值設爲-1
來禁用「預檢」緩存。
接收到服務器經過「預檢」的響應後,客戶端會正式發送真正的請求,接下來的處理方式和簡單請求一致。
在當前開發中,當不須要兼容老式瀏覽器中,咱們通常採用CORS的方式進行跨域請求,由於相比Websocket,CORS支持非長鏈接場景;相比JSONP,CORS支持全部HTTP請求,用法更加平滑。
固然,值得一提的是,當你須要兼容老式瀏覽器時,JSONP是你惟一的選擇~