今日大雨,公交车上看到关注的某前端微信公众号,推送了一条消息。结尾是'你知道几种跨域请求的方式?‘脑子一闪貌似在曾经的面试中也遇到过类似的问题。了解了一下便不再理会了。今天又重新提出来,花了两个小时重新温习理解一下旧的东西。记录下来如有不足还请大神们指出。
最初始的jsonp
- 原生js
var script = document.createElement('script');
script.type = 'text/javascript';
// 传参并指定回调执行函数为onBack
script.src = 'http://www.domain2.com:8080/login?user=admin&callback=onBack';
document.head.appendChild(script);
// 回调执行函数
function onBack(res) {
alert(JSON.stringify(res));
}
- ajax原理
$.ajax({
url: url,
dataType: 'jsonp',
type: 'get',
sucess: function() {
.....
},
error:
})
但是有一个缺点就是:只能实现get一种请求,显然不能满足我们的需求。
空的iframe + form (发送请求,没有返回值)
//--------简写并不完整
const requestPost = (url, data) => {
//首先先创建一个用于发送数据的iframe
const iframe = document.createElement('iframe');
iframe.name = 'iframePost';
iframe.style.display = 'none';
document.body.appendChild(iframe);
const form = document.createElement('form');
const node = document.createElement('input');
form.action = url;
form.target = iframe.name;
form.method = 'post',
}
原理 利用form的action和target属性向iframe发送数据,搭配iframe标签的跨域能力,实现跨域并且是提交无刷新。
iframe跨域 (分为主域相同,子域不同时和主域不相同时)
-
主域相同,子域不同
先来举个栗子说明什么样的是主域相同而子域不同 (比如www.baidu.com和https://baike.baid… 父窗口:
<iframe id="iframe" src="http://child.domain.com/b.html"></iframe>
<script>
document.domain = 'domain.com';
var user = 'admin';
</script>
子窗口:
<script>
document.domain = 'domain.com';
// 获取父窗口中变量
alert('get js data from parent ---> ' + window.parent.user);
</script>
原理:主域相同子域不同的条件下,实现跨域请求变量,两个域都需要设置域名 document.domain=‘xxxx’
-
主域不相同
- location.hash +iframe跨域 实现原理:想要A域与B域相互跨越通信,通过只能中间页C来实现。三个页面,不同域之间利用location.hash传值,相同域直接js访问通信 具体实现:A域(a.html)->B域(b.html)->A域(c.html),A与B不同域通过hash值单向传递,B与C不同域只能单向从B向C传递,但是A与C同域,C可通过parent.parent访问页面的所有对象。
a.html:www.yuhior1.com/a.html
<iframe id="iframe" src="http://www.yuhior2.com/b.html" style="display: none;"></iframe>
<script>
var iframe = document.getElementById('iframe');
setTimeout(function() {
iframe.src = iframe.src + '#user = admin';
}, 1000);
//提供同域c.html的回调方法
function oncallback(res) {
alert('data from c.html---->' + res);
}
</script>
b.html:www.yuhior2.com/b.html
<iframe id="iframe" src="http://www.yuhior1.com/c.html" style="display: none;"></iframe>
<script>
var iframe = document.getElementById('iframe');
//监听a.html传过来的hash值,然后在传给c.html
window.onhashchange = function() {
iframe.src = iframe.src + location.hash;
};
</script>
c.html:www.yuhior1.com/c.html
<script>
//监听b.html传过来的hash值
window.onhashchange = function() {
//再通过操作同域下a.html的js回调将结果返回
window.parent.parent.onCallback('hello' + location.hash.replace('#user=', ''));
};
</script>
- window.name+iframe跨域 实现原理:window.name的不同之处在于:name值在不同的页面甚至不同的域名,加载后依旧存在,并且可以支持非常长的name值大约为2MB 具体实现原理:假设index.html页面需要请求远端服务器的数据,我在该页面下建一个iframe,它的src属性指向服务器文件地址(iframe标签的跨域能力),服务器文件里设置好window.name的值(也就是该iframe的contentWindow的name),然后在index.html里读取iframe的window.name的值。但是仅仅这样不能成功,因为index.html页面和该页面里边的iframe框架src不同域,则也就无法操作框架里边的东西,自然也就获取不到iframe的name值了,所以采用上边location.hash +iframe的思想 使用一个中间页面 ,在index.html同源下新建一个proxy.html 空页面
上代码:
<script type="text/javascript">
iframe = document.createElement('iframe');
iframe.style.display = 'none';
var state = 0;
//防止onload事件之后,重置src ,重新载入页面,再触发onload事件
iframe.onload = function() {
if (state === 1) {
var data = JSON.parse(iframe.contentWindow.name);
console.log(data);
iframe.contentWindow.document.write('');
iframe.contentWindow.close();
document.body.removeChild(iframe);
} else if (state === 0) {
state = 1;
iframe.contentWindow.location = 'http://localhost:81/cross-domain/proxy.html';
}
};
iframe.src = 'http://localhost:8080/data.php';
document.body.appendChild(iframe);
</script>
未完待续......
* * *