跨域获取数据的方法

579 阅读4分钟

跨域-1: 服务器中转请求,让服务端请求非同源的数据,提供接口给页面

跨域-2: 设置基础域名(domain)+IFrame

非常重要的前提:2个页面的基础域名一定要一样才行。

var ajaxDomain = (function() {
	function creatIframe(frameId, frameUrl) {
		var frame = document.createElement('iframe');
		frame.id = frameId;
		frame.src = frameUrl;
		frame.style.display = 'none';
		return frame
	}
	return function(opt) {
		document.domain=opt.basicUrl;
		var frame = creatIframe(opt.frameId, opt.frameUrl)
		document.body.appendChild(frame);
		frame.onload = function() {
			var $$ = frame.contentWindow.parent.$;
			$$.get(opt.url, opt.success, opt.error)
		}
	}
}())

                                     

ajaxDomain({
	basicUrl:'hellojs.com',//是基础域名
	url: 'https://myapi.hellojs.com/product',
	frameId: 'itest',
	frameUrl: 'https://myapi.hellojs.com/home',
	success: function(res) {
		console.log(res);
	},
	error: function(err) {
		console.log(err);
	}
})

跨域-3: 利用window.name+Iframe的特点实现

window.name的特点:

1、每一个浏览器窗口都有一个全局的对象window(iframe框架的全局对象是contentWindow);

2、每一个window对象都有一个唯一的name属性;

3、在页面关闭之前(声明周期之内),所有的页面共享同一个name属性,该属性可读可写。

4、在在页面关闭之前,无论加载什么页面,都不会改变name的值,除非加载的页面进行重新设置。

5、name属性存储的数据约为2M的字符串

iframe的特点:

6、iframe窗口的内部不受同源策略规则的限制,iframe也是一个窗口,iframe也是一个窗口,iframe也是一个窗口,如下图:就是在父窗口里面用2个ifram窗口渲染出来的2个页面:

<iframe src="https://www.hao123.com/"></iframe>
<iframe  src="https://juejin.cn/"></iframe>

image.png

问题:怎么样让父窗口获取不同源页面的name属性?由于浏览器同源策略的限制,直接访问是不可能的。但是iframe是不受同源策略规则的限制。

解决方案:

1、父窗口先用iframe去加载非同源的页面A,让页面A去请求与API同源的数据(页面A必须与数据源的API同源,否则页面A也是拿不到数据的),通过window.name属性缓存起来;

2、页面A加载完毕之后,由于父窗体是不能直接访问A页面,让iframe跳转到与父窗口同源的页面B,页面B其实什么都没有做,纯粹是为了与A共享一个name属;实现了数据共享的桥梁。

3、页面B加载完成之后。这时父窗口就可以通过iframe的contentWindow拿到页面B的name属性了。

代码如下:

父窗口的代码:my.onload执行2次:

第1次加载的是A页面,

第2次加载的是B页面


<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<iframe id="myIframe" src="A.html"></iframe>
		<script type="text/javascript">
			var my=document.getElementById('myIframe');
			var flag=false;
			my.onload=function(){
				if(flag){
				render(my.contentWindow.name);
				}else{
					flag=true;
					setTimeout(function(){
						my.contentWindow.location='B.html'
					},1000)
				}
			}
			function render(res){
				console.log(res);
			}
			
		</script>
	</body>
</html>

页面A的代码:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<script type="text/javascript">
			window.name = '我把数据拿回来了,放在name属性上'
		</script>
	</body>
</html>

页面B的代码:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
	</body>
</html>

跨域-4: 利用postMessage+Iframe实现

同样是利用Iframe去请求数据,通过postMessage(data,ulr)给父窗体发送数据。

跨域-5: 利用hash+Iframe实现:

1、iframe加载也与父窗体不同源的界面A,让该页面A去请求数据。

2、数据拿回来之后,然后通过改变hash+数据,跳转到与父窗体同源的iframe页面B。

3、页面B修改父窗体的的hash+数据。

跨域-6: cors 跨域:

跨域资源共享:Cross-origin resource sharing

服务端设置header:Access-Control-Allow-Origin

任意域名:header("Access-Control-Allow-Origin:*")

单域名:header("Access-Control-Allow-Origin:www.baidu.com")

多域名:

跨域-7: JSonp跨域: jsonp:json with padding跨域获取json数据的一种非官方使用模式

1、json是一种数据格式;

2、jsonp:是获取不同站点json数据的技术;

jsonp主要是利用:img、link、iframe、script不受同源策略规则的限制。

缺点:只支持get请求

封装代码如下:


function getDataByJSonp(opt) {
	var temp = document.createElement('script');
	temp.src = setSrc();
	document.body.appendChild(temp)
	temp.remove();
	if (!window.hasOwnProperty(opt.data.callback)) {
		window[opt.data.callback] = function(res) {
			opt.success(res)
		}
	}
	function setSrc() {
		var str = '';
		for (let key in opt.data) {
			str += key + '=' + opt.data[key] + '&'
		}
		str = str.slice(0, -1)
		return opt.url.includes('?') ? opt.url + str : opt.url + '?' + str
	}
}
			
var tbUrl = 'https://suggest.taobao.com/sug';
getDataByJSonp({
	url: tbUrl,
	data: {
		q: 'b',
		callback: 'cb',
	},
	success: function(res) {
		console.log(res);
	}
})

jsop查询站点:

api.asilu.com/

image.png

总结

跨域请求数据的必要条件:请求数据的页面必须与数据源同源。

1、与前端无关的2种跨域:

1-1、服务端中转请求,

2-2、服务端接口设置请求头header,允许跨域请求,cors

2、委托iframe请求 + domain 2-1、iframe+domain:当前的页面的基础域名必须与iframe加载的页面的基础域名一致。

3、前端委托iframe请求+iframe共享桥梁的3种方法

3-1、iframe+name:iframe加载与数据同源的页面A,A页面把数据设置在name属性,页面A加载完毕,iframe通过设置contentWindow.location属性跳转到与当前窗体同源的B页面。

3-2、iframe+ hash

3-3、 iframe+ postMessage

4、JSONP 实现跨域

利用script标签不受同源策略限制的规则,加载非同源脚本,非同源同步执行本地函数