CORS即Cross Origin Resource Sharing(跨來源資源共享),通俗說就是我們所熟知的跨域請求。眾所周知,在以前,跨域可以采用代理、JSONP等方式,而在Modern瀏覽器面前,這些終將成為過去式,因為有了CORS。
CORS在最初接觸的時候只大概了解到,通過服務器端設置Access-Control-Allow-Origin響應頭,即可使指定來源像訪問同源接口一樣訪問跨域接口,最近在使用CORS的時候,由於需要傳輸自定義Header信息,發現原來CORS的規范定義遠不止這些。
CORS可以分成兩種:
1、簡單請求
2、復雜請求
一個簡單的請求大致如下:
HTTP方法是下列之一
HEAD
GET
POST
HTTP頭信息不超出以下幾種字段
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type,但僅能是下列之一
application/x-www-form-urlencoded
multipart/form-data
text/plain
任何一個不滿足上述要求的請求,即被認為是復雜請求。一個復雜請求不僅有包含通信內容的請求,同時也包含預請求(preflight request)。
簡單請求的發送從代碼上來看和普通的XHR沒太大區別,但是HTTP頭當中要求總是包含一個域(Origin)的信息。該域包含協議名、地址以及一個可選的端口。不過這一項實際上由瀏覽器代為發送,並不是開發者代碼可以觸及到的。
簡單請求的部分響應頭及解釋如下:
Access-Control-Allow-Origin(必含)- 不可省略,否則請求按失敗處理。該項控制數據的可見范圍,如果希望數據對任何人都可見,可以填寫"*"。
Access-Control-Allow-Credentials(可選) – 該項標志着請求當中是否包含cookies信息,只有一個可選值:true(必為小寫)。如果不包含cookies,請略去該項,而不是填寫false。這一項與XmlHttpRequest2對象當中的withCredentials屬性應保持一致,即withCredentials為true時該項也為true;withCredentials為false時,省略該項不寫。反之則導致請求失敗。
Access-Control-Expose-Headers(可選) – 該項確定XmlHttpRequest2對象當中getResponseHeader()方法所能獲得的額外信息。通常情況下,getResponseHeader()方法只能獲得如下的信息:
Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma
當你需要訪問額外的信息時,就需要在這一項當中填寫並以逗號進行分隔
如果僅僅是簡單請求,那么即便不用CORS也沒有什么大不了,但CORS的復雜請求就令CORS顯得更加有用了。簡單來說,任何不滿足上述簡單請求要求的請求,都屬於復雜請求。比如說你需要發送PUT、DELETE等HTTP動作,或者發送Content-Type: application/json的內容。
復雜請求表面上看起來和簡單請求使用上差不多,但實際上瀏覽器發送了不止一個請求。其中最先發送的是一種"預請求",此時作為服務端,也需要返回"預回應"作為響應。預請求實際上是對服務端的一種權限請求,只有當預請求成功返回,實際請求才開始執行。
預請求以OPTIONS形式發送,當中同樣包含域,並且還包含了兩項CORS特有的內容:
Access-Control-Request-Method – 該項內容是實際請求的種類,可以是GET、POST之類的簡單請求,也可以是PUT、DELETE等等。
Access-Control-Request-Headers – 該項是一個以逗號分隔的列表,當中是復雜請求所使用的頭部。
顯而易見,這個預請求實際上就是在為之后的實際請求發送一個權限請求,在預回應返回的內容當中,服務端應當對這兩項進行回復,以讓瀏覽器確定請求是否能夠成功完成。
復雜請求的部分響應頭及解釋如下:
Access-Control-Allow-Origin(必含) – 和簡單請求一樣的,必須包含一個域。
Access-Control-Allow-Methods(必含) – 這是對預請求當中Access-Control-Request-Method的回復,這一回復將是一個以逗號分隔的列表。盡管客戶端或許只請求某一方法,但服務端仍然可以返回所有允許的方法,以便客戶端將其緩存。
Access-Control-Allow-Headers(當預請求中包含Access-Control-Request-Headers時必須包含) – 這是對預請求當中Access-Control-Request-Headers的回復,和上面一樣是以逗號分隔的列表,可以返回所有支持的頭部。這里在實際使用中有遇到,所有支持的頭部一時可能不能完全寫出來,而又不想在這一層做過多的判斷,沒關系,事實上通過request的header可以直接取到Access-Control-Request-Headers,直接把對應的value設置到Access-Control-Allow-Headers即可。
Access-Control-Allow-Credentials(可選) – 和簡單請求當中作用相同。
Access-Control-Max-Age(可選) – 以秒為單位的緩存時間。預請求的的發送並非免費午餐,允許時應當盡可能緩存。
一旦預回應如期而至,所請求的權限也都已滿足,則實際請求開始發送。
通caniuse.com得知,目前大部分Modern瀏覽器已經支持完整的CORS,但IE直到IE11才完美支持,所以對於PC網站,還是建議采用其他解決方案,如果僅僅是移動端網站,大可放心使用。