CORS 理解(不要那么多术语)

摘要

谈到跨域,不论前端仍是后端,多少有点谈虎色变,面试中也常会问到这些问题,浏览器和服务器端到底怎么作才能跨域,他们都作了什么?html

同源 vs 跨域

同源,字面意义是相同的源头,即同一个web服务器(好比tomcat启动的一个实例),比如一个家庭;跨域就是从一个web服务器向另外一个服务器发送或获取数据,比如去邻居家拿东西。之因此要作跨域限制,是为了安全,你不能从邻居家直接拿吧,总得问过人家。前端

那么怎么来判断同源?就看一个web服务器的根本三要素:协议、web服务器域名、端口号。web

好比:当前页面的地址是http://myhost.com:8080/index,源就是http://myhost.com:8080,当新请求的协议、域名、端口号与之彻底一致便是同源,不然是跨域。面试

对于下面发送的请求,浏览器的判决以下:ajax

  • http://www.myhost.com:8080/users 跨域 -> 域名必须彻底一致
  • https://myhost.com:8080/users 跨域 -> 协议必须一致
  • https://myhost.com:9000/users 跨域 -> 端口必须一致
  • https://myhost.com/users 跨域 -> 端口必须一致(没有端口也是不一致)
  • https://myhost.com:8080/profile/users 同源

跨域时的动做

浏览器端

假设咱们点击一个按钮去获取数据,获取数据的请求准备从浏览器发出,这时浏览器先会检测这条请求是同源仍是跨域,也就是与按钮所在页面的地址是同源仍是跨域,若是是同源,好说,直接发送出去;若是是跨域的请求,那就得hold住先,浏览器会在请求的http header中加上一个Origin字段,标明这个请求是从哪里发出来的,例如: Origin:http://neighbour.com:9000,这样服务器端好辨识是本身家人来取东西,仍是隔壁老王来借东西了。json

那些作检测、加header字段等事情全是浏览器作,对于前端开发者来讲,什么事都不用干,ajax请求平时怎么发送,跨域时还怎么发送。可见,跨域对于前端没影响,关键在于服务器端。后端

服务器端

每一个web服务器就像一个家庭。好邻居要吃螃蟹来借点醋,这没问题;坏邻居家有醋要来借点螃蟹,这不干。跨域

服务器收到请求会给与响应,响应的header里写明跨域的配置信息,告诉浏览器,它容许哪些域名发来的请求访问,哪些method能够执行。浏览器收到响应后自动判断能不能真正执行请求。浏览器

假设服务器域名是http://rich.com:8080,它收到了一个从http://neighbour.com:9000发来的请求http://rich.com:9000/borrow-vinegar,服务器响应它,在响应中写明本服务器支持哪些域名能够访问,哪些method能够执行,浏览器收到后作匹配,再断定。缓存

那么,服务器有哪些断定的规则呢?

是否容许跨域的断定

一个支持CORS的web服务器,有以下的断定字段,他们会在响应的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

其中Access-Control-Allow-Origin(访问控制之容许的源),在响应的http header中必须有的,表示容许访问本服务器的源头Origin(域名),能够是特定的域名列表,用逗号分隔,也能够是通配符 *,表示支持任意域名的访问。

除了限定源头Origin,还会限制请求的方法MethodHeader

如,若是服务器设定Access-Control-Allow-Methods:GET,那么跨域的POST请求没法在这个服务器执行。

总流程

  • 页面发送请求
  • 浏览器根据同源策略作出断定,若是是同源请求,直接发送出去;若是是跨域请求,在HTTP HEADER加上Origin字段,或是先发送一次预检请求(preflight)。
  • 服务器接收请求,根据自身跨域的配置(如容许哪些域名,什么样的Method访问),返回文件头。若未配置过任何容许跨域,则文件头里不包含Access-Control-Allow-origin字段,若配置过域名,则返回Access-Control-Allow-origin+ 对应配置规则里的域名的方式。
  • 浏览器接收到响应,根据响应头里的`Access-Control-Allow-origin字段作匹配,若是没有这个字段,说明不匹配;若是有,将字段内容和当前域名作比对。如匹配,则能够发送请求。

跨域的请求形式

跨域的请求分两种,一种是简单请求,一种是非简单请求(废话)。

  • 简单请求,方法仅限于 HEAD,GET或POST,且Header的字段不超过如下字段:

    • HeadeAccept
    • Accept-Language
    • Content-Language
    • Last-Event-ID
    • Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain (没有application/json, 说明若是发送JSON格式的body请求数据是一个非简单请求)
  • 非简单请求就是其余请求

简单请求浏览器会直接在请求的Header加上Origin字段再发送;非简单请求浏览器则会先发送一次预检请求,根据预检请求的结果,决定是否正式发送请求。

详情能够访问阮一峰的日志:跨域资源共享 CORS 详解

相关文章
相关标签/搜索