同源策略是浏览器最核心也是最基本的安全的功能。所谓同源,指的是协议、域名、端口号都相同,不同源的客户脚本(JavaScript)在没有明确授权的情况下,只能读写本域下的资源,不能读写对方的资源;
2. 什么是跨域?跨域有几种实现形式?
跨域是指突破JavaScript同源策略的限制, a.com
域名下的 js
可以操作 b.com
或者 child.a.com
下的对象中的数据。
实现形式:
-
降域(最简单形式);对于主域相同子域不同(
http://www.a.com/
,http://child.a.com
)的情况,可以同时设置两个域名下 html 文件(index1.html
,index2.html
)document.domain = a.com
,然后在index1.html
中创建一个iframe
,去控制iframe
的contentDocument
,这样就实现了不同子域的跨域。iframe
和相同主域
是其限制条件; -
JSONP 跨域:由于直接用
XMLHttpRequest
请求不同域上的数据是不可以的。这种方式主要是通过动态插入一个script
标签。浏览器对script
的资源引用没有同源限制,同时资源加载到页面后会立即执行(没有阻塞的情况下)。 -
CORS(Cross-Origin Resource Sharing):跨域资源共享,IE需要10以上。
-
HTML5 postMessage
3. jsonp 的原理是什么?
由于直接用 XMLHttpRequest
请求不同域上的数据是不可以的。这种方式主要是通过动态插入一个 script
标签。浏览器对 script
的资源引用没有同源限制,同时资源加载到页面后会立即执行(没有阻塞的情况下)
举个栗子说明:
a.com
域名下的 index.html
文件
<body>
<script src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script>
<script type="text/javascript">
// jsonp跨域
function callback(json) {
console.log(json);
}
//动态创建一个script标签
var s = document.createElement('script');
//把a.json的URL赋给它
s.src = 'http://b.com/a.js';
//把这个script标签插入dom里
document.body.appendChild(s);
</script>
</body>
由于 jQuery
将 jsonp 封装在了 ajax 方法中,上面也可以写为:
<body>
<script src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script>
<script type="text/javascript">
$.ajax({
url: 'http://b.com/a.js',
dataType: 'jsonp',
jsonpCallback: 'callback',
success: function (ret) {
console.log(ret);
}
});
</script>
</body>
b.com
域名下的 a.js
文件
callback({
"name": "aaa",
"age": 20
});
正常情况下是不能访问的,会报跨域错误,这里用到了 jsonp
,实现了跨域访问 a.js
,得到了 b.com
下的数据:
Object {name: "aaa", age: 20}
需要注意的是 jsonp 是 get 形式的,无法使用 post,承载的信息量有限,信息量较大时请使用更强大的 CORS。
4. CORS是什么?
CORS 全称是跨域资源共享(Cross-Origin Resource Sharing),是一种 ajax
跨域请求资源的方式,支持现代浏览器,IE支持10以上。
实现方式很简单,当你使用 XMLHttpRequest
发送请求时,浏览器发现该请求不符合同源策略,会给该请求加一个请求头: Origin
,后台进行一系列处理,如果确定接受请求则在返回结果中加入一个响应头: Access-Control-Allow-Origin
; 浏览器判断该相应头中是否包含 Origin
的值,如果有则浏览器会处理响应,我们就可以拿到响应数据,如果不包含浏览器直接驳回,这时我们无法拿到响应数据。所以 CORS
的表象是让你觉得它与同源的 ajax
请求没啥区别,代码完全一样。
【练习】
1. 本地搭建服务器,演示同源策略
- 本地搭建服务器(如果使用 SAE 可创建不同的代码版本,这样可通过1.xxx.sinapp.com和2.xxx.sinapp.com 访问了)
- 修改 本地host,通过不同域名访问本地服务器。比如访问
http://a.com/index.html
,http://b.com/ajax.php
,本质是在index.html
里使用ajax
接口访问http://b.com/ajax.php
里的数据。 - 查看输出报错
通过 XAMPP
搭建本地服务器,编辑 host
:
- 127.0.0.1 a.com
- 127.0.0.1 b.com
这样通过 http://a.com
和 http://b.com
两个不同域名可以访问本地服务器
编辑 http://a.com/index.html
<body>
<h1>a.com</h1>
<script src="http://apps.bdimg.com/libs/jquery/1.9.1/jquery.js"></script>
<script>
var start = 1;
$.ajax({
type: 'get',
url: '//b.com/ajax.php',
data: {
start: start,
len:5
},
success: function(ret) {
if(ret.status === 1){
alert('success to get data!');
start += 5;
}else {
alert('failed to get data!');
}
},
error: function(){
alert("Something error");
}
});
</script>
</body>
在 a.com
下我们通过 index.html
中的 ajax
访问 b.com
下的 ajax.php
编辑 http://b.com/ajax.php
<?php
// 后端 php 测试接口文件
$start = $_GET['start']; //1
$len = $_GET['len']; //5
$items = array();
for($i = 0; $i < $len; $i++){
array_push($items, '内容' . ($start+$i));
}
$ret = array('status'=>1, 'data'=>$items);
//{status: 1, data: ['内容1','内容2','内容3']}
sleep(0.5);
echo json_encode($ret);
浏览器输入 a.com
,看到报错信息:
2. 至少使用一种方式解决跨域问题
- JSONP 解决跨域
a.com
下的 html 请求 b.com
下的 php
编辑 http://a.com/index.html
<script src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script>
<script type="text/javascript">
$.ajax({
url: 'http://b.com/a.php',
dataType: 'jsonp',
success: function (ret) {
console.log("I'm " + ret.name + ",and I'm " + ret.age + " years old.");
},
error: function () {
alert("Something error");
}
});
编辑 http://b.com/a.php
<?php
$jsondata = '{
"name": "aaa",
"age": 20
}';
echo $_GET['callback'].'('.$jsondata.')';
result
I'm aaa,and I'm 20 years old.
- CORS 解决跨域
a.com
下的 html 请求 b.com
下的 php
编辑 http://a.com/index.html
<script src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script>
<script type="text/javascript">
$.ajax({
url: 'http://b.com/a.php',
// dataType: 'jsonp',
success: function (ret) {
console.log("I'm " + ret.name + ",and I'm " + ret.age + " years old.");
},
error: function () {
alert("Something error");
}
});
编辑 http://b.com/a.php
header("Access-Control-Allow-Origin:http://a.com");
<?php
$jsondata = '{
"name": "aaa",
"age": 20
}';
echo $_GET['callback'].'('.$jsondata.')';
result
I'm aaa,and I'm 20 years old.
注:本文内容来自互联网,旨在为开发者提供分享、交流的平台。如有涉及文章版权等事宜,请你联系站长进行处理。