由于浏览器同源策略(协议、域名、端口)的限制,当浏览器向跨源服务器发起请求时,会出现跨域。
解决跨域的方式有多种,比如jsonp、CORS、Iframe、nginx正、反向代理等。
本文着重介绍CORS。
介绍:
CORS全称是跨域资源共享。需要浏览器和服务器的同时支持。目前所有浏览器都支持,IE需要10以上。
整个通信过程都是浏览器自动完成的,前端开发者不需要做任何设置,关键在于服务器端。
当浏览器发现请求跨域时,就会自动添加一些头部信息,有时会多出一次请求(预检请求),对用户是无感知的。
请求方式
CORS的请求方式有两种,简单请求和非简单请求(需要预检请求)。
1、简单请求
条件:
同时符合以下两个条件为简单请求:
- 请求方式
- GET
- POST
- HEAD(只获取报文首部)
- 除了浏览器自己在Http头上加的信息(如Host、Connection、User-Agent等)之外,开发者只能加下列字段:
- Accept
- Accept-Language
- Content-Language
- DPR
- Downlink
- Save-Data
- Viewport-Width
- Width
- Content-Type 值仅限于三个之一(text/plain、multipart/form-data、application/x-www-form-urlencoded)
流程:
当浏览器发现是跨源请求时,会自动在头部增加Origin
字段,用来说明请求源(协议、域名、端口),服务器会根据该字段值决定是否允许请求。
如果Origin不在服务器的允许的范围,服务器会返回正常的HTTP响应,但响应头中如果不包含Access-Control-Allow-Origin
字段,浏览器发现没有该字段便会抛出错误。需要注意的是,这种错误无法通过状态码识别,因为HTTP响应的状态码有可能是200。
如果Origin在允许的范围内,服务器会在响应头中多出以下字段:
-
Access-Control-Allow-Origin
:必选。值要么是请求时Origin字段的值,要么是一个*
,表示接受任意域名的请求。 -
Access-Control-Allow-Credentials
,可选。值为boolean, 表示是否允许浏览器发送cookie,如果不需要,不设置该字段即可。如果要发送,还需要服务器同意,响应头设置Access-Control-Allow-Credentials: true
,同时ajax对象设置该属性ajax.withCredentials = false
-
Access-Control-Expose-Headers
,可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。
注意: 如果要发送Cookie,Access-Control-Allow-Origin
就不能设为星号,必须指定明确的、与请求网页一致的域名。
非简单请求(需预检请求)
所谓非简单请求是对服务器有特殊要求的请求,比如:
请求方法是:
- PUT 传输文件
- DELETE 删除文件
- CONNECT 要求用隧道协议连接代理
- OPTIONS 询问支持的方法
- TRACE 路径追踪
或 Content-Type
字段的类型是application/json
或包含自定义请求头。
非简单请求会在正式通信之前,增加一次HTTP查询请求,称为“预检请求”。
流程:
预检请求必须首先使用Options
方式发起请求,获取当前的Origin
是否在服务器允许的范围,以及支持的请求方式等。
请求头中除了设置Oirgin
字段,还需两个字段:
-
Access-Control-Request-Method
:必选,告诉服务器实际请求将使用的请求方式 -
Access-Control-Request-Headers
:可选,值为逗号分割的字符串,告诉服务器实际请求将携带两个自定义头信息
当服务器收到预检请求后,检查了Origin
、Access-Control-Request-Method
和 Access-Control-Request-Headers
字段以后确认是否允许跨源请求,如果有一项不满足则不允许跨源请求,浏览器会在控制台抛出错误。如果都满足,预检请求的响应头中会包含以下字段:
-
Access-Control-Allow-Origin
:必选,值为请求头中的Origin -
Access-Control-Allow-Methods
:必选,值为逗号分隔的字符串,表示允许跨域请求的请求方式 -
Access-Control-Allow-Credentials
:可选,值为boolean, 表示是否允许浏览器发送cookie,详情同简单请求 -
Access-Control-Allow-Headers
:可选, 允许跨域请求额外发送的header字段 -
Access-Control-Max-Age
:可选,预检请求的有效时间。在有效时间内,浏览器无须为同一请求再次发起预检请求。需要注意的是,浏览器自身维护了一个最大有效时间,如果该首部字段的值超过了最大有效时间,将不会生效。
服务器通过了“预检”请求以后,就可以发起实际请求了,每次请求都会有一个Origin
头信息字段。服务器的回应,也都会有一个Access-Control-Allow-Origin
头信息字段。
网友评论