为什么会有跨域问题
- 浏览器同源策略
- 跨域是浏览器的限制,抓包工具能获取到数据
- 浏览器发现AJAX请求跨域,会自动添加一些附加头信息,有时会多出一次请求,但用户不会有感觉。
- 导致跨域情况
总结:不同协议、不同域名(主域、子域)、不同端口都会导致跨域
如何解决跨域
- jsonp
- nginx 反向代理
- CORS(跨域资源共享)
访问控制场景(简单请求与非简单请求)
简单请求
-
使用方法之一:
- GET
- POST
- HEAD
-
请求的header
- Accept
- Accept-Language
- Content-Language
- Content-Type
- text/plain
- multipart/form-data
- application/x-www-form-urlencoded
使用 Origin 和 Access-Control-Allow-Origin 就能完成最简单的访问控制。服务端返回的 Access-Control-Allow-Origin: * 表明,该资源可以被任意外域访问
非简单请求
非简单请求对服务的要求不同,比如请求方法为 PUT、DELETE 。 或者Content-Type 为 application/json
1. 预检请求
- 使用 OPTIONS 方法,询问。预检请求需要三个字段
- Access-Control-Request-Method 告知服务器,实际请求使用的方法
- Access-Control-Request-Headers 告知服务器,实际请求携带的请求首部字段
- Origin 表示请求来自的那个域
2.预检响应
- 服务器收到预检请求后,检查了Origin,Access-Control-Request-Method,Access-Control-Request-Headers字段后,确认允许跨域,就可以做出回应
- 如果浏览器否认了“预检”请求,会返回一个正常的HTTP回应,但是没有任何CORS相关的头部信息字段,浏览器会认为不同意,触发一个错误
- 服务器回应的其他CORS字段
- Access-Control-Allow-Methods: 必需,逗号分隔的字符串,表示服务器支持的所有跨域请求方法;
- Access-Control-Allow-Headers:浏览器支持的所有头部字段;
- Access-Control-Allow-Credentials:true
- Access-Control-Allow-Max-Age: 指定本次请求的有效期;
withCredentials 属性
- CORS默认不发送Cookie和HTTP认证信息,如果要把Cookie 发送到服务器,一方面需要服务器同意,设置响应头
Access-Control-Allow-Credentials:true;
另一方面,客户端发送请求时,也要进行一些设置,例如 xhr.withCredentials = true;
服务器如何设置CORS
-
如果请求为简单请求
- 直接设置响应头 Access-Control-Allow-Origin 为 *,或者具体的域名;
如果响应头Access-Control-Allow-Credentials 为 true,则此时Access-Control-Allow-Origin 不能设置为*,必须指定明确的域名;
-
如果请求为非简单请求
- 处理 OPTIONS 请求,服务端可以单独写一个路由
- 可以把这部分抽离处理,作为一个中间件,例如Koa