1、什么是跨域
在前端领域中,跨域是指浏览器允许向服务器发送跨域请求,从而克服浏览器同源限制
1.1 什么是同源策略?
同源策略是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源是指”协议+域名+端口”三者相同,即便两个不同的域名指向同一个ip地址,也非同源。
同源策略限制以下几种行为:
- Cookie、LocalStorage 和 IndexDB 无法读取
- DOM和JS对象无法获得
- xhr请求不能发送
2、常见的跨域场景
URL | 说明 | 是否允许通信 |
---|---|---|
1. www.domain.com/a.js 2. www.domain.com/b.js 3. www.domain.com/lab/c.js | 同一域名,不同文件或路径 | 允许 |
1. www.domain.com:8000/a.js 2. www.domain.com/b.js | 同一域名,不同端口 | 不允许 |
1. http://www.domain.com/a.js 2. http://192.168.4.12/b.js | 域名和域名对应相同ip | 不允许 |
1. http://www.domain.com/a.js 2. http://x.domain.com/b.js 3. http://domain.com/c.js | 主域相同,子域不同 | 不允许 |
3、跨域的解决方案
3.1 JSONP跨域
jsonp的原理就是利用<script>标签没有跨域限制,通过<script>标签src属性,发送带有callback参数的GET请求,服务端将接口返回数据拼凑到callback函数中,返回给浏览器,浏览器解析执行,从而前端拿到callback函数返回的数据。
缺点:jsonp的缺点:只能发送get一种请求。
1 | // 前端 |
3.2 跨域资源共享(CORS)
CORS是一个W3C标准,全称是”跨域资源共享”(Cross-origin resource sharing)。
它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。
浏览器将CORS跨域请求分为简单请求和非简单请求。
A、只要同时满足一下两个条件,就属于简单请求:
- 使用下列方法之一:head、get、post
- 请求的Heder是:
- Accept
- Accept-Language
- Content-Language
- Content-Type: 只限于三个值:application/x-www-form-urlencoded、multipart/form-data、text/plain
对于简单请求,浏览器直接发出CORS请求。具体来说,就是在头信息之中,增加一个Origin字段。
B、复杂请求:
非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json。非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为”预检”请求(preflight)。
预检请求
预检”请求用的请求方法是OPTIONS,表示这个请求是用来询问的。请求头信息里面,关键字段是Origin,表示请求来自哪个源。除了Origin字段,”预检”请求的头信息包括两个特殊字段。
1)Access-Control-Request-Method:必选
2)Access-Control-Request-Headers:可选
3.3 nginx代理跨域
nginx代理跨域,实质和CORS跨域原理一样,通过配置文件设置请求响应头Access-Control-Allow-Origin等字段。
1)nginx配置解决iconfont跨域
浏览器跨域访问js、css、img等常规静态资源被同源策略许可,但iconfont字体文件(eot|otf|ttf|woff|svg)例外,此时可在nginx的静态资源服务器中加入以下配置。
2)nginx反向代理接口跨域
3.4 nodejs中间件代理跨域
3.5 document.domain + iframe跨域
此方案仅限主域相同,子域不同的跨域应用场景。实现原理:两个页面都通过js强制设置document.domain为基础主域,就实现了同域。
1 | // 父窗口 |
3.6 postMessage跨域
postMessage是HTML5 XMLHttpRequest Level 2中的API,且是为数不多可以跨域操作的window属性之一,它可用于解决以下方面的问题:
- 页面和其打开的新窗口的数据传递
- 多窗口之间消息传递
- 页面与嵌套的iframe消息传递
1 | // a.html (www.domain1.com/a.html) |