跨域請求整體分爲兩種類型:簡單請求和複雜請求,即simple request和preflight request。ajax
1、簡單請求spring
simple request的請求須要,知足如下條件:跨域
1.請求方法只能是GET,HEAD,POST瀏覽器
2.Accept、Accept-Language、Content-Language、Content-Type、DPR、Downlink、Save-Data、Viewport-Width、Width服務器
3.第二個條件中的Content-Type只能是application/x-www-form-urlencoded、multipart/form-data、text/plain其中的一種app
4.沒有特殊js代碼(參考https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Simple_requests)url
對於simple request請求,儘管這個請求是跨域的,它也會被瀏覽器直接放行。spa
可是瀏覽器拿到response後並不會把 response 直接暴露給用戶程序,而是去檢查這個 response 的 headers 中有沒有 Access-Control-Allow-Origin
,以及這個 header 的 value 包含 request 發出的地址(也就是「域」)。code
若是兩個條件都知足, response 會被返回給發出請求的程序;若是沒有這個 header 或者 value 不對, response 就會被攔截下來,由於在瀏覽器看來,這個 response 不屬於你,由於服務器沒有明確容許你這個「域」來請求它。orm
2、複雜請求
對於複雜請求,瀏覽器先發送一個pre-flight請求,一般是一個OPTIONS方法的請求,根據服務器響應的response的headers進行校驗,若校驗經過,則代表服務器容許訪問,再發送真正的請求。
一般要校驗的數據項有:Access-Control-Allow-Origin
, Access-Control-Allow-Methods、Access-Control-Allow-Headers以及其餘的
Access-Control-*數據項。
下面是咱們的一個跨域請求示例。本機63342端口的網頁經過ajax訪問8080端口的接口,存在跨域問題。
第一個是pre-flight請求,服務器收到請求並響應,response header中返回了Access-Control-Allow-Origin、Access-Control-Allow-Methods以及Access-Control-Allow-Headers等,
表示當前服務器容許http://localhost:63342域的GET請求(而且該請求包含name爲authorization的header數據)訪問。若是不符合該條件則真正的請求不會被髮送。
由於咱們的請求符合服務器所要求的的條件,因此真正的請求被髮送,請求數據以下:
我麼能夠看到請求成功,一個完整的跨域請求就完成了。
spring4.2以後提供了@CrossOrigin註解來代表接口的跨域特性。
springMVC的請求流程是Request->Dispatchservlet->HandlerMappin(uri和handler的映射關係)->HandlerAdapter(適配器用於執行handler)->ModerAndView->ViewResolver->Response
CrossOrigin註解在HandlerAdapter階段起做用,當檢測到請求是preflight請求(知足三個條件,請求方法爲OPTIONS、請求head包含Origin和Access-Control-Request-Method)時,
spring給本次請求適配的handler是PreFlightHandler實例,該handler專門處理preflight請求,判斷是否拒絕訪問或者容許訪問時容許訪問的域、請求方法、請求必須的header。
真正的請求發送以後就是則會通過CorsInterceptor攔截器,其前置方法preHandle也會對跨域請求進行校驗,校驗經過則設置一些響應數據頭,而後交給下一級攔截器或者controller處理,校驗不經過則響應瀏覽器禁止訪問。