引言
跨域,顾名思义,就是一个域发送请求访问另一个域。
什么是域?
域就是协议名(如http)+主机名(如www.baidu.com)+端口号(如80)。只有这三部分一样,才能算是同一个域
跨域的方法常用的有四种:分别是JSONP、iframe标签跨域、代理服务器跨域、CORS跨域
JSONP跨域
众所周知,在HTML页面中的< img >、< link >、< script >等标签的src属性是不受跨域请求限制。所以我们可以通过动态生成
// 动态创建script标签
var script = document.createElement('script');
// 随机生成函数名,不然会读取本地缓存的js文件
var time = new Date();
var funcName = 'jsonp'+time.getTime();
// 拼接URL,判断URL中是否传有参数
if(url.indexOf('?')>0){
// 如果url中传有参数,这样拼接URL
url = url + '&callback' + funcnName;
}else{
// 如果url中没有参数,这样拼接URL
url = url + '?callback' + funcnName;
}
// 注册回调函数到全局
window[funcName] = function(data){
callback(data); // 这里的回调函数自己设定
//调用完回调函数后销毁我们注册的函数和创建的script标签
delete window[funcName];
script.parentNode.removeChild(script);
}
// 设置script标签的src属性
script.setAttribute('src',url);
// 把script标签加入head,请求服务器得到数据
document.getElementsByTagName('head')[0].appendChild(script);
使用JSONP需注意
要注意回调函数的名称。我们需要和后台确定一个callback参数(作确定回调函数名用),方便后台调用前端写的回调函数
JSONP的缺点
①无法发送POST请求
②想确定JSONP请求是否失败并不容易,大多数确定方法都是结合超时时间来判断
③JSONP是可执行脚本,可能存在安全隐患
④对于一些第三方API接口,他们不像和我们约定好的后台那样会读取callback参数。他们只返回JSON或者XML数据,也就是我们平常像后台要的数据一样,只是他是跨域的。这种时候,JSONP形式获取数据就不合适了
iframe标签跨域
这个方法的关键在于window的name属性。该属性的特性在于,同个窗口的所有页面使用的都是同一个window.name属性,并且不会因为刷新和新页面的载入而重置,但是每个页面都可以读取和修改这属性!所以我们可以使用这个属性作为中介,存放接收的数据
// 客户端
<body>
<button onclick="getData()">点击发起跨域请求数据</button>
<iframe id="iframe" src="http://localhost:3000/xxx/xxx/index?name=John" style="display:none"></iframe>
// 只是利用iframe获取跨域数据,所以样式设置不显示
</body>
<script>
function getData(){
// 获取iframe元素
var iframe = document.getElementById('iframe');
// 设置为空白页,就不存在域了(即没有跨域问题),如果不设置的话,iframe的src和本地的是不同域的,也就是还存在跨域问题
iframe.src = 'about:blank';
//让iframe重新加载一次,地址就变成我们同域了(任何空白页和任何域都同域)
iframe.onload = function(){
// iframe中的contentWindow对象相当于我们正常打开页面的window对象,获取它的name值
var data = iframe.contentWindow.name;
data = JSON.parse(data); // 转为JSON格式
alert(data.name);
}
}
</script>
// 服务端
app.get('/xxx/xxx/index',function(req,res){
let param = req.query.name;
var data = {name:param};
var data = JSON.stringify(data);
res.send('<script>window.name='+data+';</script>');
});
iframe标签跨域缺点
不支持POST访问
代理服务器处理跨域
我们需要知道的是,跨域问题只存在于浏览器中,服务器之间的访问不存在跨域问题。所以我们可以通过后台访问需要跨域访问的url,然后让后台返回数据给前端就行了。
CORS跨域
其是W3C推出的一种新机制,基于浏览器的一个内置机制,需要浏览器支持。所以其实现方法只需要和正常的AJAX一样,不需要额外的代码,浏览器支持该机制的话,就会自动帮你跨域,不支持就会报错。但需要满足以下要求
- 请求方式要用:HEAD、POST、GET
- 数据类型 Content-Type 只能是application/x-www-form-unlencoded、multipart/form-data或text/plain中的一种
- 不使用自定义的请求头