之前写的安卓程序,并不存在跨域这种说法,是可以自由的从不同的域名下请求数据的,现在看前端知识,则就出现了跨域这个概念。了解跨域,主要清楚以下的知识点就可以。
- 什么是同源策略,满足同源策略的三个条件是什么
- 跨域的具体方案是什么,怎么处理。
什么是同源策略,满足同源策略的三个条件是什么
浏览器为了安全起见,制定了同源策略,只允许在本域名下的数据请求操作,同源策略主要要求以下三个条件
- 协议相同,注意http和https是不同的协议
- 域名相同
- 端口一致
请求的url和当前html的url满足以上三个条件就是同源的,非同源的情况下,使用数据就会受到限制。
跨域的具体方案是什么,怎么处理
实际场景中,我们不可能什么东西都放在自己的域名下来处理,比如我们可能需要一个天气请求的API,但是我们的主业是电商,那我们很可能就需要一个第三方的API来做。这个时候我们就不得不跨域。目前主流的跨域的方案有一下三类。
JSONP
JSONP是JSON with padding的简称。我们知道 Script 标签中的js不受同源策略的影响,我们可以自由加载任何域名下的js来执行。JSONP就是以此为契机建立的。具体的我们在执行的时候可以这么做
在html端
1
2
3
4
5<script src = "https://a.imzy.me?callback = getWeather">
function getWeather(data){
console.log(data)
}
</script>在服务端返回的时候 带上 callback({data: xxx})。
前后端配合,实现JSONP。不过以上的做法显得有些tricking。最主要的缺点是他只可以进行get请求。
CROS
CROS的意思是跨域资源共享,这种跨域的方法是对ajax的拓展。
CROS机制是浏览器发现请求的链接和当前页面url是不同源的,就主动在请求头中添加一个Origin的头,然后后端设置一个Access-Control-Allow-Origin的响应头。响应头中带有服务端允许的域。允许的域和Origin中的域能对应上就可以使用CROS。主要需要后端设置响应头。
详细解释下,Origin头说明的是当前请求来自于哪个域,ACAO则说明的是服务端允许的域。
可以参考 CROS.
和iframe有关的行为
在html页面上,我们也可以使用iframe来嵌套另一个html页面。我们的主页面,一般是不允许控制iframe中的元素的,除非iframe和我们的主页面是同一个域。不过iframe确实存在需要跨域的场景。和iframe有关的跨域主要分为以下两种
降域。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46a.html
<html>
<style>
.ct{
width: 910px;
margin: auto;
}
.main{
float: left;
width: 450px;
height: 300px;
border: 1px solid #ccc;
}
.main input{
margin: 20px;
width: 200px;
}
.iframe{
float: right;
}
iframe{
width: 450px;
height: 300px;
border: 1px dashed #ccc;
}
</style>
<div class="ct">
<h1>使用降域实现跨域</h1>
<div class="main">
<input type="text" placeholder="http://a.nany.com:8080/a.html">
</div>
<iframe src="http://b.imzy.vip:8080/b.html" frameborder="0" ></iframe>
</div>
<script>
//URL: http://a.imzy.vip:8080/a.html
document.querySelector('.main input').addEventListener('input', function(){
console.log(this.value);
window.frames[0].document.querySelector('input').value = this.value;
})
document.domain = 'imzy.vip'
</script>
</html>以下是iframe中的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21<html>
<style>
html,body{
margin: 0;
}
input{
margin: 20px;
width: 200px;
}
</style>
<input id="input" type="text" placeholder="http://b.imzy.vip:8080/b.html">
<script>
// URL: http://b.imzy.vip:8080/b.html
document.querySelector('#input').addEventListener('input', function(){
window.parent.document.querySelector('input').value = this.value;
})
document.domain = 'imzy.vip';
</script>
</html>注意以上代码中,a.imzy.vip和b.imzy.vip是不同的域名。但是他们的后缀是一样的,所以可以降域为imzy.vip
PostMessage
主要使用的是iframe的postMessage方法,来进行iframe的通信。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>跨域POST消息发送</title>
<script type="text/JavaScript">
// sendPost 通过postMessage实现跨域通信将表单信息发送到 指定的域名上,
// 并取得返回的数据
function sendPost() {
// 获取id为otherPage的iframe窗口对象
var iframeWinow = document.getElementById("otherPage").contentWindow;
// 向该窗口发送消息
iframeWin.postMessage(document.getElementById("message").value,
'http://imzy.vip');
}
// 监听跨域请求的返回
window.addEventListener("message", function(event) {
console.log(event, event.data);
}, false);
</script>
</head>
<body>
<textarea id="message"></textarea>
<input type="button" value="发送" onclick="sendPost()">
<iframe
src="http://imzy.vip/other-domain.html" id="otherPage"
style="display:none"></iframe>
</body>
</html>放在另一个域名下的iframe内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>POST Handler</title>
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
<script type="text/JavaScript">
window.addEventListener("message", function( event ) {
// 监听父窗口发送过来的数据向服务器发送post请求
var data = event.data;
$.ajax({
// 注意这里的url只是一个示例.实际练习的时候你需要自己想办法提供
type: 'POST',
url: 'http://imzy.vip/getData',
data: "info=" + data,
dataType: "json"
}).done(function(res){
//将请求成功返回的数据通过postMessage发送给父窗口
window.parent.postMessage(res, "*");
}).fail(function(res){
//将请求失败返回的数据通过postMessage发送给父窗口
window.parent.postMessage(res, "*");
});
}, false);
</script>
</head>
<body></body>
</html>以上是通过PostMessage来进行iframe通信的实例,主要是完成了,从主界面发送消息到子iframe,子iframe中监听消息,将数据使用window.parent.postMessage()方法,回传数据的过程。