CORS原理

CORS

在浏览器中,基于一些安全原因,对JavaScript脚本的执行添加了同源(相同协议,域名与端口)策略的限制。在一个页面使用JavaScript发起一个请求时,浏览器会检测当前请求的URL是否与当前页面的URL同源,如果不是,一般情况下会禁止次请求执行得到响应的结果。

CORS 的请求

为请求头添加Origin属性,标记当前发出请求的页面所在域,服务端检测请求头中的Origin,如果是可信的请求源,则可以在该请求的响应头中添加Access-Control-Allow-Origin,内容为请求的Origin,表明允许当前Origin进行块玉请求,也可以为*,表示允许所有的Origin进行跨域请求。

CORS标准吧跨预请求分为简单请求和非简单请求。当响应头满足以下条件,则被视为简单请求:

请求方法为GET,POST,HEAD,请求头只包含一下属性

  • Accept:客户端可接收的MediaType
  • Accept-Language:客户端可接收的语言
  • Content-Lanuage:客户端请求内容的语言
  • Last-Event-ID:最后一次事件ID
  • Content-Type:客户端请求内容的MediaType,当且仅当MediaType为application/x-www-form-urlencoded,multipart/form-data,text/plain三者之一时才视为简单请求。

浏览器在发送时,会自动判断请求类型,并作出相应的处理。

简单请求的发送与处理

对于简单请求,浏览器在发送时,会在请求头中为其自动添加Origin属性,用于表示请求来源,值为请求页面URL中的协议,域名和端口信息。

响应头

  • Access-Control-Allow-Origin:必须返回,值一般为请求的Origin,但根据配置也可能是*,表明允许所有来源进行逗号分隔。
  • Access-Control-Request-Credentials:该属性可选,默认是false。用于表明是否允许浏览器将Cookie信息包含在CORS请求中。对于XMLHttpRequest,如果需要包含Cookie信息,则还需要设置withCredentials属性为true,请求才会包含Cookie的信息
  • Access-Control-Expose-Headers:允许请求方的JS脚本通过Response获取的头属性列表,默认包含6个基本属性,分别是:Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, Pragma。如果需要让CORS请求头可以访问其他属性,则需要通过响应头设置属性列表。

一旦请求方需要发送Cookie信息,响应头中的Access-Control-Allow-Origin不能为*,只能为请求方的Origin。

非简单请求的发送与处理

在浏览器检测到当前CORS请求是非简单请求时,会先向服务器发送一个预检请求(preFlight)预检请求通过之后,才会发送正式的数据请求。

预检请求

预检请求是一个请求方法为OPTIONS的请求,不携带任何请求题,只携带一些预本次CORS请求相关的元信息,如CORS请求方法,包含哪些请求头等信息。服务器端更具预检请求里的这些信息,判断是否允许该CROS请求,只有预检请求得到了服务器的肯定回答,才允许正式请求,否则这次请求会直接报错。

预检请求头

  • Access-Control-Request-Method: 请求头一定存在,表示本次CORS请求的请求方法。
  • Access-Control-Request-Headers:表示CORS请求除了简单请求中请求头之外,额外包含的请求头属性列表。

响应头

  • Access-Control-Allow-Origin:必须返回,值一般为请求的Origin,但根据配置也可能是*,表明允许所有来源进行逗号分隔。
  • Access-Control-Request-Methods:表示可接受CORS请求的方法列表,用于逗号隔开,返回多个可以避免多次预检,浏览器会对预检结果进行缓存
  • Access-Control-Request-Headers:表示可接受的请求头列表,不包括简单请求头中的基本请求头
  • Access-Control-Request-Credentials:和简单请求相同
  • Access-Control-Max-Age:可选属性。表示此次预检结果的有限时长,浏览器会对预检结果进行缓存,该属性表示缓存时间,单位为秒

如果服务器不接受CORS请求,在预检响应不包含这些属性,浏览器就认为不允许跨预请求。

当预检请求通过之后,真正的请求就与简单请求一样,包含Origin的请求头,响应中包含Access-Control-Allow-Origin。

阅读 75

推荐阅读