一、什么是跨域
广义的跨域包括:
- 资源跳转:超链接<a>跳转、重定向、表单提交
- 资源嵌入:link、ifram、script、img,以及css样式中的background:url()、@font-face()等外链接
- 脚本请求:js的ajax请求、js或DOM 中的跨域操作
狭义的跨域:指浏览器同源策略限制的请求
注意:并不是所有广义的跨域操作都不被允许,只有被同源策略限制的跨域操作是不被允许的
二、什么是浏览器同源限制
浏览器为了安全考虑不允许访问不同域下的资源
注意两点:
- 同源限制只是浏览器的安全策略,不是http协议的内容
- 对于向不同域下发起的请求,浏览器会照常发出,服务端处理后也会正常返回结果,但结果会在返回后被浏览器拦截
浏览器判断同源的标准:
- 请求协议相同
- 请求域名相同(包括父子域名都相同,特别注意:域名与对应IP不是同源)
- 端口号相同
同源限制访问那些内容:
- cookie、LocalStorage、IndexDB等存储信息无法读取
- DOM对象无法获取
- Ajax请求无法完成
三、处理跨域的方法
1、JSONP
原理:使用<script>可以跨域加载资源。浏览器端定义回调方法处理返回数据,跨域请求参数带回调方法名;服务端需要返回方法名定义的方法,参数为需要的数据,这样浏览器接收后直接以数据为参数调用回调方法
// 浏览器端 function fn(data) { console.log('在这里处理返回数据:' + data) } <script src="http://a.com/get-date?jsonp=fn"></script> // 服务器端返回数据格式 fn({name: 'zhangs', age: 18})
优点:没有兼容性问题
缺点:只支持get请求
2、CORS
原理:在高版本的浏览器中,发现ajax请求跨域后会在请求头部添加额外信息或添加额外请求(预检请求option),这样只要服务端发现跨域请求后在返回头部通知浏览器允许哪些站点跨域请求即可
过程:
- CORS在浏览器端代码没有任何区别,浏览器识别到跨域请求后自动对其进行处理,用户没有感知。
- 服务端处理后,在响应头部添加Access-Control-Allow-Origin,指定允许请求的源
- 浏览器收到响应后根据Access-Control-Allow-Origin判断本站点是否在允许范围内,允许则接收数据继续后续操作
确定:兼容性不如jsonp(IE10以上支持)
优点:基本满足http所有Method类型,也可以指定部分支持Method
3、WebSocket
WebSocket是支持服务端与客户端双向通信的应用层(与HTTP同层)协议,基于TCP协议。WebSocket在建立连接时需要借助http,但连接建立后双方通信过程与http协议无关。
通过WebSocket与跨域服务建立连接,就可以完成跨域请求
优点:协议自定义,减少数据内容
确定:主要用于双向通信的场景,否则长连接有一定的内存消耗
兼容性IE10以上,不过目前,对于低版本有一定的降级处理途径,也有Socket.io可以使用
4、postMessage
html5为了解决不同源不能获取DOM元素的问题,为window对象添加了postMessage方法。
window.postMessage('这里是要发送的信息', 'http://192.168.xxx.xx:3000/')
第一个参数:发送的内容
第二个参数:接收消息的源,包括协议类型、域名、端口号
5、nginx跨域处理
第一种:静态资源添加Access-Control-Allow-Origin配置,原理同CORS(主要针对字体文件跨域请求,css、js等不受同源策略限制)
location / { add_header Access-Control-Allow-Origin *; }
第二种:nginx反向代理解决跨域
实现思路:通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录
#proxy服务器 server { listen 81; server_name www.domain1.com; location / { proxy_pass http://www.domain2.com:8080; #反向代理 proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名 index index.html index.htm; # 当用webpack-dev-server等中间件代理接口访问nignx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用 add_header Access-Control-Allow-Origin http://www.domain1.com; #当前端只跨域不带cookie时,可为* add_header Access-Control-Allow-Credentials true; } }
参考文档:
跨域几种方式:https://juejin.im/post/5b04eae06fb9a07ac4806139
前端常见跨域解决方案(全):https://juejin.im/entry/59b8fb276fb9a00a42474a6f