爲何會有跨域??
因爲瀏覽器的同源策略限制,瀏覽器會拒絕跨域請求,那麼什麼是同源呢?
若是兩個頁面的協議,端口,和域名都相同,則兩個頁面具備相同的源。若是3者有一個不一樣,則爲跨域。html
頁面可能會因某些限制而改變他的源。腳本能夠將document.domain的值設置爲其當前域或者當前域的超級域。若是將其設置爲其當前域的超級域,則較短的域將用於後續源檢查。假設http://store.company.com/dir/...:
document.domain = "company.com"ajax
這條語句執行以後,頁面將會成功地經過對http://company.com/dir/page.h...(假設http://company.com/dir/page.h...)。json
這裏必須兩個頁面都設置document.domain才能經過同源策略。這是由於設置document.domain都會致使端口口號被重寫爲null。(即便document.domain= document.domain).只有子域和父域都設置document.domain。才能確保端口號都爲null。api
同源策略控制了不一樣源之間的交互,例如在使用xmlhttpRequest或img標籤時候則會受到同源策略的約束,這些交互一般分爲3類
1 一般容許跨域寫操做(cross-origin whites) 。例如重定向表單提交等
2 一般容許跨域資源嵌入(cross-orgin embedding). 例如img <script> <iframe>
3 一般不容許跨域讀操做(cross-origin reads)。但常能夠經過內嵌資源來巧妙的進行讀取訪問。
例如能夠讀取嵌入圖片的高度和寬度和jsonp內嵌腳本的方式。跨域
使用cors容許跨域訪問。(cross-origin resource sharing)瀏覽器
瀏覽器將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)服務器
凡是不一樣時知足上面兩個條件。就屬於非簡單請求。瀏覽器對這兩種請求的處理,是不同的。cookie
瀏覽器發現這個跨域ajax請求是簡單請求,就自動在頭信息之中,添加一個origin。網絡
若是origin指定的源,不在許可範圍內,服務器會返回一個正常的http迴應。瀏覽器發現,這個迴應的頭沒有包含access-control-allow-origin字段。就知道出錯了。從而拋出一個錯誤,被xmlhttprequest onerror回調函數捕獲。注意,這種錯誤沒法經過狀態碼識別,由於http迴應的狀態碼有多是200.。
Access-Control-Allow-Origin: http://api.bob.com
該字段必須,它的值要麼是請求的origin的值,要麼是*.表示接受任意域名的請求。
Access-Control-Allow-Credentials: true
字段可選,表示是否發送cookie。默認狀況下,cookie不包括在cors請求之中
設爲true,表示服務器明確許可,coookie能夠包含在請求中,一塊兒發給服務器。
這個值也只能爲true,若是服務器不要瀏覽器發送cookie,刪除該字段便可。
另外ajax請求也必須打開withCredentials屬性
var xhr = new XMLHttpReqeust();
xhr.withCredentials = true;
不然,即便服務器贊成發送cookie。瀏覽器也不會發送。可是若是省略withCredentials設置,
有的瀏覽器仍是會一塊兒發送cookie。這時能夠顯式關閉withCredentials = false;
**
須要注意,若是要發送cookie。access-control-allow-origin就不能設爲星號。必須指定明確一致的域名。同時cookie依然遵循同源政策,只有用服務器域名設置的cookie纔會上傳,其餘域名的cookie並不會上傳,且原網頁代碼中的document.cookie也沒法讀取服務器域名下的cookie.
**
Access-Control-Expose-Headers: FooBar
該字段可選。CORS請求時,XMLHttpRequest對象的getResponseHeader()方法只能拿到6個基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。若是想拿到其餘字段,就必須在Access-Control-Expose-Headers裏面指定。上面的例子指定,getResponseHeader('FooBar')能夠返回FooBar字段的值。
非簡單請求時那種對服務器有特殊要求的請求,好比請求方式是put或delete。或者
content-type字段的類型是application/json
非簡單請求的cors請求,會在正式通訊以前,增長一次http查詢請求,稱爲預檢請求(preflight)。
瀏覽器先詢問服務器,當前網頁所在的域名是否在服務器的許可名單之中,已經可使用那些http動詞和頭信息。只有獲得確定答覆,瀏覽器纔會發出正式的xmlhttprequest請求,不然就報錯。
OPTIONS /cors HTTP/1.1 Origin: http://api.bob.com Access-Control-Request-Method: PUT Access-Control-Request-Headers: X-Custom-Header Host: api.alice.com Accept-Language: en-US Connection: keep-alive User-Agent: Mozilla/5.0...
預檢請求用的請求方式是optioons,表示這個請求時用來詢問的。頭信息裏面,關鍵字段是origin,表示請求來着那個源。
除了origin字段,預檢請求的頭信息包括兩個特殊字段。
access-control-request-method 該字段是必須的,用來列出瀏覽器cors請求會用到哪些http方法。
access-control-request-headers。 該字段是一個逗號分隔的字符串,指定瀏覽器cors請求會額外發送的頭信息字段。
HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 01:15:39 GMT Server: Apache/2.0.61 (Unix) Access-Control-Allow-Origin: http://api.bob.com Access-Control-Allow-Methods: GET, POST, PUT Access-Control-Allow-Headers: X-Custom-Header Content-Type: text/html; charset=utf-8 Content-Encoding: gzip Content-Length: 0 Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Content-Type: text/plain
上面迴應中,關鍵字段是
access-control-allow-origin
access-control-allow-methods
access-control-allow-headers
一般返回200 後者204.
204與200的不一樣就是。204不須要攜帶多餘的響應體,節省流量
若是瀏覽器否認了預檢請求。會返回一個正常的http迴應,可是沒有任何
cors相關的頭信息字段。
服務器迴應的其餘cors相關字段以下
Access-Control-Allow-Methods: GET, POST, PUT Access-Control-Allow-Headers: X-Custom-Header Access-Control-Allow-Credentials: true Access-Control-Max-Age: 1728000
1)Access-Control-Allow-Methods
該字段必需,它的值是逗號分隔的一個字符串,代表服務器支持的全部跨域請求的方法。注意,返回的是全部支持的方法,而不單是瀏覽器請求的那個方法。這是爲了不屢次"預檢"請求。
(2)Access-Control-Allow-Headers
若是瀏覽器請求包括Access-Control-Request-Headers字段,則Access-Control-Allow-Headers字段是必需的。它也是一個逗號分隔的字符串,代表服務器支持的全部頭信息字段,不限於瀏覽器在"預檢"中請求的字段。
(3)Access-Control-Allow-Credentials
該字段與簡單請求時的含義相同。
(4)Access-Control-Max-Age
該字段可選,用來指定本次預檢請求的有效期,單位爲秒。上面結果中,有效期是20天(1728000秒),即容許緩存該條迴應1728000秒(即20天),在此期間,不用發出另外一條預檢請求。
一旦服務器經過了預檢請求,之後每次瀏覽器正常的cors請求,就都跟簡單請求同樣,會有一個origin頭信息字段,服務器的迴應,也都會有一個access-control-allow-origin頭信息字段。
與jsonp的比較
cors與jsonp的使用目的相同,可是比jsonp更強大jsonp只支持get 請求。cors支持全部類型的http請求。jsonp的優點在於支持老式瀏覽器以及能夠不支持cors的網站請求數據。