CORS 參考
http://enable-cors.org/index.html https://help.aliyun.com/document_detail/oss/practice/cors_guide.html
同源策略
跨域訪問,或者說JavaScript的跨域訪問問題,是瀏覽器出於安全考慮而設置的一個限制,即同源策略。當來自於A網站的頁面中的JavaScript代碼希望訪問B網站的時候,瀏覽器會拒絕該訪問,因為A,B兩個網站是屬於不同的域。
在實際應用中,經常會有跨域訪問的需求,比如用戶的網站www.a.com,后端使用了OSS。在網頁中提供了使用JavaScript實現的上傳功能,但是在該頁面中,只能向www.a.com發送請求,向其他網站發送的請求都會被瀏覽器拒絕。這樣就導致用戶上傳的數據必須從www.a.com中轉。如果設置了跨域訪問的話,用戶就可以直接上傳到OSS而無需從www.a.com中轉。
CORS介紹
跨域資源共享(Cross-Origin Resource Sharing),簡稱CORS,是HTML5提供的標准跨域解決方案,具體的CORS規則可以參考W3C CORS規范。
CORS是一個由瀏覽器共同遵循的一套控制策略,通過HTTP的Header來進行交互。瀏覽器在識別到發起的請求是跨域請求的時候,會將Origin的Header加入HTTP請求發送給服務器,比如上面那個例子,Origin的Header就是www.a.com。服務器端接收到這個請求之后,會根據一定的規則判斷是否允許該來源域的請求,如果允許的話,服務器在返回的響應中會附帶上Access-Control-Allow-Origin這個Header,內容為www.a.com來表示允許該次跨域訪問。如果服務器允許所有的跨域請求的話,將Access-Control-Allow-Origin的Header設置為*即可,瀏覽器根據是否返回了對應的Header來決定該跨域請求是否成功,如果沒有附加對應的Header,瀏覽器將會攔截該請求。
以上描述的僅僅是簡單情況,CORS規范將請求分為兩種類型,一種是簡單請求,另外一種是帶預檢的請求。預檢機制是一種保護機制,防止資源被本來沒有權限的請求修改。瀏覽器會在發送實際請求之前先發送一個OPTIONS的HTTP請求來判斷服務器是否能接受該跨域請求。如果不能接受的話,瀏覽器會直接阻止接下來實際請求的發生。
只有同時滿足以下兩個條件才不需要發送預檢請求:
請求方法是如下之一:
GET
HEAD
POST
所有的Header都在如下列表中:
Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma
預檢請求會附帶一些關於接下來的請求的信息給服務器,主要有以下幾種:
Origin:請求的源域信息
Access-Control-Request-Method:接下來的請求類型,如POST、GET等。
Access-Control-Request-Headers:接下來的請求中包含的用戶顯式設置的Header列表。
服務器端收到請求之后,會根據附帶的信息來判斷是否允許該跨域請求,信息返回同樣是通過Header完成的:
Access-Control-Allow-Origin:允許跨域的Origin列表
Access-Control-Allow-Methods:允許跨域的方法列表
Access-Control-Allow-Headers:允許跨域的Header列表
Access-Control-Expose-Headers:允許暴露給JavaScript代碼的Header列表。
Access-Control-Max-Age:最大的瀏覽器緩存時間,單位s。
瀏覽器會根據以上的返回信息綜合判斷是否繼續發送實際請求。當然,如果沒有這些Header瀏覽器會直接阻止接下來的請求。
這里需要再次強調的一點是,以上行為都是瀏覽器自動完成的,用戶無需關注這些細節。如果服務器配置正確,那么和正常非跨域請求是一樣的。
Java Web服務器配置
maven依賴
<dependency> <groupId>com.thetransactioncompany</groupId> <artifactId>cors-filter</artifactId> <version>2.5</version> </dependency>
web.xml加入配置
<filter> <filter-name>CORS</filter-name> <filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class> <init-param> <param-name>cors.allowOrigin</param-name> <param-value>*</param-value> </init-param> <init-param> <param-name>cors.supportedMethods</param-name> <param-value>GET, POST, HEAD, PUT, DELETE</param-value> </init-param> <init-param> <param-name>cors.supportedHeaders</param-name> <param-value>Accept, Origin, X-Requested-With, Content-Type, Last-Modified</param-value> </init-param> <init-param> <param-name>cors.exposedHeaders</param-name> <param-value>Set-Cookie</param-value> </init-param> <init-param> <param-name>cors.supportsCredentials</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>cors.maxAge</param-name> <param-value>3600</param-value> </init-param> </filter> <filter-mapping> <filter-name>CORS</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
其他跨域方案
document.domain方案,前提是必須是同一個基域名
iframe