为什么会有跨越问题?
因为所有支持Javascript的浏览器都会使用同源策略这个安全策略。
同源策略,它是由Netscape提出的一个著名的安全策略。现在所有支持JavaScript 的浏览器都会使用这个策略。
所谓同源是指,域名,协议,端口相同。当一个浏览器的两个tab页中分别打开来 百度和谷歌的页面当一个百度浏览器
执行一个脚本的时候会检查这个脚本是属于哪个页面的,即检查是否同源,只有和百度同源的脚本才会被执行。
下面介绍5种解决跨域的方法
1. 通过jsonp跨域
利用页面上可以引入不同域上的js脚本文件。步骤如下:
1. 浏览器端注册callback回调函数。
2. 然后动态生成一个 script 标签,src 为:请求资源的地址+获取函数的字段名+回调函数名称。
3. 让服务端拿到回调函数名称,填充数据返回一段js代码给浏览器
4. 浏览器执行
具体代码:
function resolveJosn(result) { //浏览器端代码
console.log(result.name);
}
var jsonpScript= document.createElement("script");
jsonpScript.type = "text/javascript";
jsonpScript.src = "http://www.qiute.com?
callbackName=resolveJson";
document.getElementsByTagName("head")[0].appendChild(jsonpScript);
php //服务器端代码
<?php
$callback = $_GET['callback']; // 获取回调函数名
$arr = array("name" => "alsy", "age" => "20"); // 要请求的数据
echo $callback."(". json_encode($arr) .");"; // 输出
?>
2. 通过修改document.domain来跨子域(iframe)
特点:这两个域名必须属于同一个基础域名!而且所用的协议,端口都要一致。
使用方法:document.domain 的设置是有限制的,我们只能把 document.domain 设置成自身或更高一级的父域,且主域必须相同。例如:a.b.example.com 中某个文档的 document.domain 可以设成a.b.example.com、b.example.com、example.com中的任意一个,但是不可以设成c.a.b.example.com,因为这是当前域的子域,也不可以设成baidu.com,因为主域已经不相同了。
具体代码:
// 主页面:http://blog.qiutc.me/a.html
<script>
document.domain = 'qiutc.me';
function onLoad() {
var iframe = document.getElementById('iframe');
var iframeWindow = iframe.contentWindow; // 这里可以获取 iframe 里面 window 对象并且能得到方法和属性
var doc = iframeWindow.document; // 获取到
iframeWindow.getData('http://www.qiutc.me/json_domain.php', '{u: "alsy-domain", age: "20"}', function(r) {
console.log(eval("(" + r + ")"));
});
} //由于json_domain.php与下面的框架同域,所以可以这样通过子域获取数据
</script>
<iframe src="http://www.qiutc.me/b.html" onload="onLoad()" </iframe>
// iframe 里面的页面(在另一个文件中)
<script>
document.domain = 'qiutc.me';
window.getData = function(url, data, cb) {
var xhr = null;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
xhr.open('POST', url, true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
cb(xhr.responseText);
}
}
xhr.send(data);
}
</script>
3. 隐藏的iframe+window.name跨域
原理:window对象有个name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name 的,每个页面对 window.name 都有读写的权限,window.name 是持久存在一个窗口载入过的所有页面中的,并不会因新页面的载入而进行重置。
比如有一个www.sdc.me/a.html页面,需要通过a.html页面里的js来获取另一个位于不同域上的页面www.baidu.com/data.html里的数据。步骤:
1.把a。html里的iframe的src设为www.baidu/data.html。
2.iframe的src设成跟a.html页面同一个域才行,这样才符合同源策略。
www.baidu.com/data.html 代码如下:
<script>
window.name = '我是被期望得到的数据';
</script>
在 a.html 页面中使用一个隐藏的 iframe 来充当一个中间人角色,由 iframe 去获取 data.html 的数据,然后 a.html 再去得到 iframe 获取到的数据。代码如下:
// a.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script>
function getData() {
var iframe = document.getElementById('iframe');
iframe.onload = function() {
var data = iframe.contentWindow.name; // 得到
}
iframe.src = 'b.html'; // 这里b和a同源
}
</script>
</head>
<body>
<iframe src="http://www.baidu.com/data.html" style="display:none" onload="getData()" </iframe>
</body>
</html>
4.frame+跨文档消息传递
window.postMessage(message,targetOrigin) 方法是html5新引进的特性,可以使用它来向其它的window对象发送消息,无论这个window对象是属于同源或不同源.
步骤:
调用postMessage方法的window对象是指要接收消息的那一个window对象,该方法的第一个参数message为要发送的消息,类型只能为字符串;第二个参数targetOrigin用来限定接收消息的那个window对象所在的域,如果不想限定域,可以使用通配符 * 。
-
需要接收消息的window对象,可是通过监听自身的message事件来获取传过来的消息,消息内容储存在该事件对象的data属性中。
// 主页面 blog.qiutc.com <script> function onLoad() { var iframe = document.getElementById('iframe'); var iframeWindow = iframe.contentWindow; iframeWindow.postMessage("I'm message from main page."); } </script> <iframe src="http://www.qiutc.me/b.html" onload="onLoad()" </iframe> // b 页面 <script> window.onmessage = function(e) { e = e || event; console.log(e.data); } </script>
5.跨域资源共享 CORS
- 服务器响应头:Access-Control-Allow-Origin它的值设置成 *,表示接受任意域名的请求。
- 如果要发送Cookie,Access-Control-Allow-Origin就不能设为*,必须指定明确的、与请求网页一致的域名。
6. WebSockets
HTML5新增的一大特性之一就是: Web Sockets 其目标是在一个单独的持久连接上提供全双工、双向通信。在 JavaScript 中创建了 Web Socket 之后,会有一个HTTP 请求发送到浏览器以发起连接。在取得服务器响应后,建立的连接会使用 HTTP 升级从 HTTP 协议交换为 WebSocket 协议。也就是说,使用标准的 HTTP 服务器无法实现 Web Sockets,只有支持这种协议的专门服务器才能正常工作。
同源策略对 Web Sockets 不适用,因此可以通过它打开到任何站点的连接。至于是否会与某个域中的页面通信,则完全取决于服务器。(通过握手信息就可以知道请求来自何方。)