标签:oss 调用 end adf 用户 none complete api 域服务器
同源策略(跨域的由来)
同源策略限制从一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的关键的安全机制。
“同源”是指:协议相同、域名相同、端口相同
同源政策的目的:是为了保证用户信息的安全,防止恶意的网站窃取数据。
同源的限制范围:
1. Cookie、LocalStorage 和 IndexDB 无法读取
2. DOM 无法获得
3. AJAX 请求不能发送
这里需要明确的一点是:所谓的域跟js的存放服务器没有关系,比如baidu.com的页面加载了google.com的js,那么此js的所在域是baidu.com而不是google.com。也就是说,此时该js能操作baidu.com的页面对象,而不能操作google.com的页面对象。
跨域的方法
一、使用JSONP跨域(单项跨域-一般用于获取数据)
原理:因为通过script标签引入的js是不受同源策略的限制的(正如前文提到的baidu.com的页面加载了google.com的js)。所以我们可以通过script标签引入一个js或者是一个其他后缀形式(如php,jsp等)的文件,此文件返回一个js函数的调用,如返回一个对象:
JSONP_getPerson({
"name":"怪诞咖啡",
"age":18,
"job":"前端攻城狮",
});
也就是说此文件返回的结果调用了JSONP_getPerson函数,并且把{"name":"怪诞咖啡","age":18,"job":"前端攻城狮"}传进去,这{"name":"怪诞咖啡","age":18,"job":"前端攻城狮"}是一个对象。此时我们的页面中有一个JSONP_getPerson函数,函数JSONP_getPerson就被调用到,并且传入了一个对象。此时就实现了在本域获取其他域数据的功能,也就是跨域。
JSONP_getPerson:前端引入远程js并定义好JSONP_getPerson函数,注意需要先定义好JSONP_getPerson函数,避免在远程js加载完成并调用JSONP_getPerson时,此函数不存在
例子代码:
<script>
function JSONP_getPerson(users) {
console.dir(users);
}
</script>
<script src="http://xxx/index.php"></script>
// 前端代码调用script标签块必须在函数标签块之后
地址说明:http://xxx/index.php,其中的xxx是表示不同域名下的文件,测试的时候,把前端和后端代码放到不同的源中测试
<?php
echo ‘JSONP_getPerson({
"name":"怪诞咖啡",
"age":18,
"job":"前端攻城狮",
})‘;//返回一个js函数的调用
?>
为什么script标签引入的文件不受同源策略的限制?
JSONP的缺点则是:
地址说明:http://xxx/getPerson.php?name=Hello&age=18,其中的xxx是表示不同域名下的文件,测试的时候,把前端和后端代码放到不同的源中测试
感悟:
二、动态创建script标签(单项跨域-一般用于获取数据)
这种方法其实是JSONP跨域的简化版,JSONP只是在此基础上加入了回调函数。比如上例中的 getPerson.php 返回的如果不是一个js函数的调用,而是一个js变量,如:
<?php echo ‘var person = {"name":"怪诞咖啡","age":18,"job":"前端攻城狮"}‘ ?>
那么在当前域下就可以取到person变量,这里需要注意判断script节点是否加载完毕,如:
<script>
var head= document.getElementsByTagName(‘head‘)[0];
var scriptPerson= document.createElement(‘script‘);
scriptPerson.type= ‘text/javascript‘;
scriptPerson.src= ‘http://xxx/index.php‘;
head.appendChild(scriptPerson);
scriptPerson.onload = scriptPerson.onreadystatechange = function() {
if (!this.readyState || this.readyState === ‘loaded‘ || this.readyState === ‘complete‘) {
console.log(person); //此处取出其他域的数据
scriptPerson.onload = scriptPerson.onreadystatechange = null;
}
};
</script>
地址说明:http://xxx/index.php,其中的xxx是表示不同域名下的文件,测试的时候,把前端和后端代码放到不同的源中测试
三、window.name属性(单项跨域-一般用于获取数据)
来源:
特征:
基本原理:
例子:(index.html经过3秒跳转到data.html)
<script>
// 页面index.html
window.name =‘我是index.html页面的window.name值‘;
setTimeout(function(){
window.location = ‘http://xxx/data.html‘;
},3000);
</script>
// 页面data.html,两者不同域名
<script>
console.log(window.name);
</script>
代码说明:实际运行中能够看到在 data.html 页面上成功获取到了,它的上一个页面 index.html 给window.name设置的值。如果在之后所有载入的页面都没对 window.name 进行修改的话,那么所有这些页面获取到的 window.name 的值都是 index.html 页面设置的那个值。当然,如果有需要,其中的任何一个页面都可以对window.name的值进行修改。注意, window.name 的值只能是字符串的形式,这个字符串的大小最大能允许2M左右,具体情况取决于不同的浏览器,但一般是够用了。
上面的例子中,我们用到的页面 index.html 和 data.html 在同域和不同域环境下都进行了测试,结果都一样,这也正是利用window.name进行跨域的原理。
问题:这样获取到的 window.name 的值需要跳转页面获取,自然不是我们想要的结果,我们想要的是页面不跳转也可以获取到数据,上面的例子是为了体现和理解 window.name 的跨域能力,这种简单的方法才更有利于初学者理解和学习。
实现不跳转请求数据:接下来我们运用 iframe+window.name 来实现,页面不跳转来获取数据,方法就是:在 index.html 页面中使用一个隐藏的 iframe 来充当一个中间人的角色,由 iframe 去获取 data.index 的数据,然后 index.html 再去得到 iframe 获取到的数据。
例子 => 三个文件:
index.html和empty.html必须在同一域,data.html为其他域的数据文件
<script>
// index.html
var state = 0,
iframe = document.createElement(‘iframe‘),
loadfn = function() {
if (state === 1) {
var data = iframe.contentWindow.name; // 读取数据
console.log(data); // 打印出‘{"name":"怪诞咖啡","age":18,"job":"前端攻城狮"}‘,是字符串类型
} else if (state === 0) {
state = 1;
iframe.contentWindow.location = "empty.html"; // 设置的代理文件
}
};
iframe.src = ‘http://xxx/data.html‘;
if (iframe.attachEvent) {
iframe.attachEvent(‘onload‘, loadfn);
} else {
iframe.onload = loadfn;
}
document.body.appendChild(iframe);
</script>
<script>
// data.html
window.name = ‘{"name":"怪诞咖啡","age":18,"job":"前端攻城狮"}‘;
</script>
地址说明:http://xxx/data.html,其中的xxx是表示不同域名下的文件,测试的时候,把前端和后端代码放到不同的源中测试
我在最初探索window.name+iframe的时候遇到的坑:把 index.html 和 empty.html 没有体现在同一域中(比如页面地址使用 http://localhost/index.html ,里面iframe 的跳转地址使用 iframe.contentWindow.location = ‘http://127.0.0.1/empty.html‘)是不可以的,检测为不是同一个域,原因请看下面介绍
localhost与127.0.0.1的区别是什么?
localhost也叫local ,正确的解释是:本地服务器
127.0.0.1在windows等系统的正确解释是:本机地址(本机服务器)
他们的解析通过本机的host文件,windows自动将localhost解析为127.0.0.1
双向跨域:两个iframe之间或者两个页面之间,一般用于获取对方数据,document.domain方式还可以直接操作对方DOM
四、document.domain(两个iframe之间或者相同一级域名不同的二级域名cookie传递,属于双向跨域)
cookie:
Cookie 是服务器写入浏览器的一小段信息,只有同源的网页才能共享。但是,两个网页一级域名相同,只是二级域名不同,浏览器允许通过设置document.domain共享 Cookie。
举例来说,A网页是 http://w1.example.com/a.html ,B网页是 http://w2.example.com/b.html ,那么只要设置相同的 document.domain ,两个网页就可以共享Cookie。
两个域名必须属于同一个基础域名!而且所用的协议,端口都要一致,否则无法利用document.domain进行跨域
iframe:
和cookie同理,都是需要设置,document.domain
<script>
document.domain = ‘example.com‘;
</script>
问题:1、安全性,当一个站点被攻击后,另一个站点会引起安全漏洞。2、如果一个页面中引入多个iframe,要想能够操作所有iframe,必须都得设置相同domain。
五、window.postMessage(两个iframe之间或者两个页面之间,属于双向跨域)
HTML5为了解决这个问题,引入了一个全新的API:跨文档通信 API(Cross-document messaging)。
这个API为 window 对象新增了一个 window.postMessage 方法,允许跨窗口通信,不论这两个窗口是否同源。
window.postMessage() 方法可以安全地实现跨源通信。通常,对于两个不同页面的脚本,只有当执行它们的页面位于具有相同的协议(通常为https),端口号(443为https的默认值),以及主机 (两个页面的模数 Document.domain 设置为相同的值) 时,这两个脚本才能相互通信。window.postMessage() 方法提供了一种受控机制来规避此限制,只要正确的使用,这种方法就很安全。
六、location.hash(两个iframe之间,属于双向跨域),又称FIM,Fragment identifier Messaging的简写
概念:片段标识符(fragment identifier)指的是,URL的#号后面的部分,比如http://example.com/x.html#fragment的#fragment。如果只是改变片段标识符,页面不会重新刷新。
下面是hash不刷新页面,更新hash的例子:
setTimeout(function(){
location.href= ‘index.html‘ + "#" + ‘{"name":"怪诞咖啡","age":18,"job":"前端攻城狮"}‘;
},1000);
window.onhashchange = checkMessage;
function checkMessage() {
var message = window.location.hash;
console.log(message.slice(1)); //{"name":"怪诞咖啡","age":18,"job":"前端攻城狮"}
}
hash实现跨域的方式:两个文件,一个 index.html 文件,一个是不同域名下的 index.php 文件
// index.html
<script>
function getData(url, fn) {
var iframe = document.createElement(‘iframe‘);
iframe.style.display = ‘none‘;
iframe.src = url;
iframe.onload = function() {
fn(iframe.contentWindow.location.hash.substring(1));
window.location.hash = ‘‘;
document.body.removeChild(iframe);
};
document.body.appendChild(iframe);
}
// get data from server
var url = ‘http://127.0.0.1/index.php‘;
getData(url, function(data) {
var jsondata = JSON.parse(data);
console.log(jsondata);
});
</script>
// index.php
<?php
$data = ‘{\"name\":\"怪诞咖啡\",\"age\":18,\"job\":\"前端攻城狮\"}‘;
echo
"
<script>
window.location = ‘http://localhost/index.html‘ + ‘#‘ + \"$data\";
</script>
"
?>
如果看懂了之前利用 window.name+iframe 跨域获取数据,那么使用 window.hash+iframe 也就很好理解了。一样都是动态插入一个iframe,然后把iframe的src指向服务端地址,而服务端同样都是输出一段js代码,同样都是利用和子窗口之间的通信完成数据传输,同样要针对同源策略做出处理。
HTML标签和跨域
看到之前的介绍,能够了解到跨域都是通过HTML标签做一些事情,HTML有:script、img、iframe、link
CSS中,有伟大的 background 属性,也可以实现跨域
跨域的方法,可以说很多很多,不仅仅局限于上面的方法,今后慢慢来总结这块
标签:oss 调用 end adf 用户 none complete api 域服务器
原文地址:http://www.cnblogs.com/liu-fei-fei/p/7821434.html