跨域請求詳解
跨域請求總體分為兩種類型:簡單請求和復雜請求,即simple request和preflight request。
一、簡單請求
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其中的一種
4.沒有特殊js代碼(參考https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Simple_requests)
對於simple request請求,盡管這個請求是跨域的,它也會被瀏覽器直接放行。
但是瀏覽器拿到response後並不會把 response 直接暴露給用戶程序,而是去檢查這個 response 的 headers 中有沒有 Access-Control-Allow-Origin
,以及這個 header 的 value 包含 request 發出的地址(也就是“域”)。
如果兩個條件都滿足, response 會被返回給發出請求的程序;如果沒有這個 header 或者 value 不對, response 就會被攔截下來,因為在瀏覽器看來,這個 response 不屬於你,因為服務器沒有明確允許你這個“域”來請求它。
二、復雜請求
對於復雜請求,瀏覽器先發送一個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處理,校驗不通過則響應瀏覽器禁止訪問。
跨域請求詳解