跨域-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>
问题:怎么样让父窗口获取不同源页面的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查询站点:
总结
跨域请求数据的必要条件:请求数据的页面必须与数据源同源。
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标签不受同源策略限制的规则,加载非同源脚本,非同源同步执行本地函数