1、为何会有跨域问题
3、简单请求和非简单请求
Ajax 按照条件能够分为两种请求方式,简单请求和非简单请求。nginx
同时知足如下两个条件,就属于简单请求
ajax
- 使用下列方法之一
- 请求的header是
- Accept
- Accept-Language
- Content-Language
- Content-Type 只限于三个值
- application/x-www-form-urlencodes
- multipart/form-data
- text/plain
对于简单请求,浏览器直接发出CORS请求。在头部字段中,增长一个Origin字段。(chrome有时会隐藏这个字段)
chrome
下面是一个项目中的ajax封装,使用的就是简单请求:json


4、CORS请求相关的字段,都以 Access-Control- 开头
- Access-Control-Allow-Origin :必选
- (一个或者多个容许跨越的)请求头Origin字段的值
- *:接受任何域名
- Access-Control-Allow-Credentials: 可选
- true:表示容许发送cookie,此时 Access-Control-Allow-Origin 不能设置为*,必须指定明确的,与请求网页一致的域名;
- 不设置该字段,不须要浏览器发送cookie
- Access-Control-Expose-Headers:可选
- 列出了哪些首部能够做为响应的一部分暴露给外部
- 默认,只有六种暴露给外部
- Cache-Control
- Content-Language
- Content-Type
- Expires
- Last-Modified
- Pragma
- 若是想让客户端能够访问到其余的首部信息,能够将他们在Access-Control-Expose-Headers里面列出来
5、withCredentials 属性
- CORS默认不发送Cookie和HTTP认证信息,若是要把Cookie 发送到服务器,一方面须要服务器赞成,设置响应头 Access-Control-Allow-Credentials:true;另外一方面,客户端发送请求时,也要进行一些设置,例如 xhr.withCredentials = true;
6、非简单请求
非简单请求就是那种对服务器有特殊要求的请求,好比请求方法为PUT 或者 DELETE,或者 Content-Type 为 application/json;跨域
预检请求和回应
非简单请求的CORS请求,会在正式通讯以前,增长一次HTTP查询请求,称为“预检”。浏览器会询问服务器,当前网页所在的域名是否在服务器的许可名单以内,以及可使用哪些 HTTP 动词和头部信息段,只有获得确定答复,才会发出正式的接口请求。不然,报错。浏览器
一、预检请求服务器
- 用 OPTIONS 方法,询问。预检请求包括三个字段
- Origin,表示请求来自哪一个域;
- Access-Control-Request-Method:必须,浏览器会使用的请求方法;
- Access-Control-Request-Headers: 浏览器发送 CORS 请求会额外发送的头部信息段;
二、预检回应cookie
- 服务器收到预检请求后,检查了Origin,Access-Control-Request-Method,Access-Control-Request-Headers字段后,确认容许跨域,就能够作出回应
- 若是浏览器否定了“预检”请求,会返回一个正常的HTTP回应,可是没有任何CORS相关的头部信息字段,浏览器会认为不一样意,触发一个错误
- 服务器回应的其余CORS字段
- Access-Control-Allow-Methods: 必需,逗号分隔的字符串,表示服务器支持的全部跨域请求方法;
- Access-Control-Allow-Headers:浏览器支持的全部头部字段;
- Access-Control-Allow-Credentials:Cookie
- Access-Control-Allow-Max-Age: 指定本次请求的有效期;
正常请求和回应
一旦经过预检请求,之后就跟简单请求同样。app
另外一个项目使用了这种方式,如下是其截图:工具



7、服务端如何设置CORS
- 若是设置请求头 Content-Type:application/x-www-form-urlencoded,则为简单请求
- 直接设置响应头 Access-Control-Allow-Origin 为 *,或者具体的域名;
- 若是响应头Access-Control-Allow-Credentials 为 true,则此时Access-Control-Allow-Origin 不能设置为*,必须指定明确的域名;
- 若是设置请求头 Content-Type:application/json,则为非简单请求
- 处理 OPTIONS 请求,服务端能够单独写一个路由
- 能够把这部分抽离处理,做为一个中间件,例如Koa;