跨域的实现方式有很多种,比较典型的两种方式jsonp和CORS可以参考我之前的博客:
添加链接描述
参考:前端常见跨域解决方案(全)
前端各种跨域(上)
前端各种跨域(下)
什么是跨域?
狭义的跨域,指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的。
- 同源:协议+端口+域名三者相同
- 同源策略限制哪些行为?
- Cookie LocalStorage和IndexDB无法读取
- DOM 和JS对象无法获得
- AJAX请求不能发送
跨域解决方案
- 通过jsonp跨域
- document.domain + iframe跨域
- location.hash + iframe跨域
- window.name + iframe跨域
- postMessage跨域
- 跨资源共享(CORS)
- nginx代理跨域
- nodejs中间件代理 跨域
- WebSocket协议跨域
1、jsonp
简单归纳:
因为<script>
标签的src属性并不被同源策略所约束,可以获取任何服务器上脚本执行,所以jsonp的实现原理主要是利用<script>
标签的src属性,局限性:只支持get方法
- 设定一个
<script>
标签 - 创建一个回调函数,允许用户传递这个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹JSON数据,完成回调
- 客户端接收到返回的js脚本,开始解析和执行
jsonp实现:参考:jsonp的原理与实现
简单实现:
function jsonp(req) {
var script = document.createElement('script');
var url = req.url + '?callback=' + req.callback.name;
script.src = url;
document.getElementsByName('head')[0].appendChild(script);
}
function hello(res) {
console.log('hello' + res.data);
}
// 使用
jsonp({
url: '',
callback: hello
})
总结:Ajax(异步javascript和xml), 是一种可实现无需重新加载整个网页的情况下,能够更新部分网页的技术,其核心是通过XMR对象获取非本页内容 => 异步通信
而jsonp的核心则是动态添加
Ajax 和 jsonp的关联
- ajax和jsonp这两种技术在调用方式上“看起来”很像,目的也一样,都是请求一个url,然后把服务器返回的数据进行处理,因此jquery和ext等框架都把jsonp作为ajax的一种形式进行了封装
- ajax和jsonp其实本质上是不同的东西。ajax的核心是通过XmlHttpRequest获取非本页内容,而jsonp的核心则是动态添加
2、document.domain + iframe跨域
实现原理:是两个页面都通过js强制设置document.domain
为基础主域,就实现了同域。
局限性:仅限主域相同,子域不同的跨应用场景。
参考:
通过document.domain + iframe解决跨域问题
3、location.hash + iframe跨域
实现原理:a.html(属于A域) 和b.html(属于B域)想要通信,通过中间页c.html(属于A域)来实现。不同域之间利用iframe的location.hash来传值,(因为改变hash值不会导致页面刷新),相同域之间直接js访问来通信。
a.html中创建一个iframe,其src指向b.html,向b.html传入hash值,b.html监听从a.html中传来的hash值,传给c.html(在b.html中创建iframe,其src指向c.html)
参考:iFrame跨域的方式
location.hash 实现跨域 iframe 自适应
优势:
- 可以解决域名完全不同的跨域
- 可以实现双向通讯
局限:
- location.hash直接暴露在URL中
- 由于URL大小的限制,数据容量和类型都有限
4、window.name + iframe跨域
5、postMessage跨域
postMessage是html5引入的API,可以更方便、有效、安全的解决这些问题。postMessage()方法允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递,即,可解决:
- 页面和其打开的新窗口的数据传递
- 多窗口之间消息传递
- 页面与嵌套的iframe消息传递
- 上面三个场景的跨域数据传递
6、跨资源共享CORS
其原理主要是通过服务端在头部信里设置Access-Control-Allow-Origin即可,前端无需设置;
若要带Cookie请求,需要前后端都进行设置,因为CORS请求默认不发送cookie和HTTP认证信息,若要把cookie发送到服务器,一方面要服务器同意,指定Access-Control-Allow-Credentials
字段,另一方面,开发者必须在AJAX请求中打开withCredentials
属性,否则,即使服务器同意发送Cookie,浏览器也不会发送。或者,服务器要求设置Cookie,浏览器也不会处理
且
- 如果要发送Cookie,Access-Control-Allow-Origin就不能设为星号,必须指定明确的、与请求网页一致的域名
- 由于同源策略的限制,所读取的Cookie为跨域请求接口所在域的cookie,而非当前页。只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且(跨源)原网页代码中的document.cookie也无法读取服务器域名下的Cookie。
局限:对于不支持CORS的浏览器无法使用该策略。
参考:CORS-阮一峰
7、nginx代理跨域
正向代理代理客户端(比如VPN),反向代理代理服务器
Nginx 是一个高性能的HTTP和反向代理web服务器其安装在目的主机端,主要用于转发客户机请求,后台有多个http服务器提供服务,nginx的功能就是把请求转发给后面的服务器,决定哪台目标主机来处理当前请求**
实现思路:通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理domain2接口(nginx 反向代理模块 proxy_pass后面跟着一个 URL,用来将请求反向代理到 URL 参数指定的服务器上,),然后domain1访问nginx中的代理服务器,请求会被转发到domain2
server {
listen 80;
server_name localhost;
## 用户访问 localhost,则反向代理到https://api.shanbay.com
location / {
root html;
index index.html index.htm;
proxy_pass https://api.shanbay.com;
}
}
8、Node.js中间件代理跨域
与nginx反向代理十分相似,只是将nginx代理服务器换成了Node服务器。
9、webSocket
webSocket本身不存在跨域问题,所以我们可以利用webSocket来进行非同源之间的通信
WebSocket 是一种通信协议,该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信,其请求头中有一个origin字段,正是因为有了Origin这个字段,所以 WebSocket 才没有实行同源政策。因为服务器可以根据这个字段,判断是否许可本次通信。如果该域名在白名单内,服务器就会做出如下回应。