跨域请求整体分为两种类型:简单请求和复杂请求,即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处理,校验不经过则响应浏览器禁止访问。