其實就是跨域請求。我們知道XHR只能訪問同一個域中的資源,這是瀏覽器的安全策略所限制,但是開發中合理的跨域請求是必須的。CORS是W3的一個工作草案,基本思想就是:使用自定義的HTTP頭部讓瀏覽器與服務器溝通,決定響應成功或失敗。
CORS需要瀏覽器和服務器同時支持,所有瀏覽器都支持該功能,IE瀏覽器在IE10以上支持。
CORS跟同源AJAX請求差別不大,主要是瀏覽器發現Ajax跨域請求時候,自動添加一些附加的頭部信息,有時多一次附加的OPTIONS預檢查請求,但用戶不會感知。
(閑話:實際項目中經常遇到Access-Control-Allow-Origin報錯,network里面請求數據時候會多請求一次methods為options方法的請求,它返回200后才真正再去請求一次真正的接口請求,這都是請求跨域時候的表現)
Important Part:CORS將請求分成兩大類,simple request(簡單請求)和not-so-simple request(非簡單請求)
簡單請求的請求方法是:HEAD GET POST其中之一
頭部信息不超過下面幾種字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:application/x-www-form-urlencoded,multipart/form-data,text/plain
不是簡單請求的就是復雜請求了。
瀏覽器處理簡單請求步驟:
直接發起CORS請求,在request header里面添加origin字段源Url(協議+域名+端口號),如果不在許可范圍內部,服務器也是返回正常的HTTP response,但是response header里面沒有包含Access-Control-Allow-Origin字段,console控制台報錯,被瀏覽器的XHR對象的onerror回調捕獲,此時的HTTP返回碼可能是200。
Origin: http://www.nczonline.net
服務器認為該請求可以接受,response Header里面就會返回Access-Control-Allow-Origin返回相同的源信息地址。
Access-Control-Allow-Origin: http://www.nczonline.net
Access-Control-Allow-Credentials:true //是否允許發送Cookie
Access-Control-Expost-Headers:FooBar //獲取request header里面額外的字段值
Content-Type:text/html;charset=utf-8
如果沒有origin信息或者信息不匹配,那么瀏覽器就駁回請求,瀏覽器的請求和響應都不包含cookie信息。
Question:為什么CORS跨域請求和響應默認不包含cookie信息?
Answer:cookie是同源共享的,既然你都跨域了,就不能使用不同域的cookie信息了。
—————————————————————————————————————
Preflighted Requests(預檢請求):
比如非簡單請求:PUT,DELETE或者Content-Type是application/json類型的請求。在正式請求之前增加一次HTTP查詢請求,稱為”預檢請求“。
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...
上面是預檢請求的HTTP requset Header參數,可以看出請求方法是OPTIONS,關鍵字Origin請求來自哪個源地址,Access-Control-Request-Method:請求方法,Access-Control-Request-Headers:逗號分隔的字符串,瀏覽器額外附加的頭部信息。
服務器收到預檢請求后,檢查origin,Access-Control-Request-Method和Access-Control-Request-Headers字段后,確認可以跨域,就返回:
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可以設為*,表示同意任意跨源請求。
__________________________________________________________________
一旦服務器通過了預檢請求,以后每次的正常CORS請求,跟簡單請求一樣,有Origin頭部信息字段,服務器的response header里面會有
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
頭部信息字段。
如果是非簡單請求的話,預檢之后的response header里面必包含Access-Control-Allow-Origin頭部信息。
————————————————————————————————————
CORS會通過預請求的透明服務器驗證(透明是指封閉不可見的)機制支持開發者使用自定義頭部,GET或POST之外的方法,不同類型的主體內容,預檢請求發送的是OPTIONS方法,頭部信息包含:
Origin
Access-Control-Request-Method
Access-Control-Request-Headers
發送請求后,OPTIONS預檢請求結束,再次進行真正的Response響應請求。
跨域請求默認是不帶憑證:cookie,HTTP認證和SSL證明的。但是可以通過設置:withCredentials屬性為true,指定某個請求應該發送憑證,然后服務器接受請求后,Response Header里面會返回:
Access-Control-Allow-Credentials:true
各個瀏覽器對CORS的支持程度不同,但是都支持簡單請求,可以通過檢查是否存在withCredentials屬性,IE的XDR跟XHR類似,實現安全可靠的跨域通信。所以可以先檢測withCredentials屬性,再檢測XDR對象是否存在,就可以兼顧所有瀏覽器了。
其他跨域技術:
圖像Ping:利用img標簽的src屬性,進行GET請求訪問,不能得到服務器的返回。適合單向通信。
JSONP:利用script標簽的src屬性,動態生成js腳本,執行服務器返回的js腳本中的帶有JSON參數的回調函數。可以通過拿到響應參數自執行回調函數,簡單有用。
——————————————————————————————————————————
CORS和JSONP使用目的相同,但是比JSONP更加強大,CORS主要是服務端配置好后,瀏覽器根據服務端配置的自定義頭部和提供的可以進行的CORS的方法來進行跨域操作
JSONP只支持GET請求,CORS支持所有類型的HTTP請求。
【完】
時光荏苒,如白駒過隙。
歲月如斯,然赤心如故。
