新手在练习Ajax的时候常常会出现“莫名其妙”的bug,代码都对,可是测试的时候控制台报错,缘由可能就是测试文件路径有问题,致使了Ajax的跨域问题。跨域问题在开发过程当中并非很常见,可是仍是有的,总结下常见的跨域访问的方法:javascript
1、利用JSONPphp
<script type="text/javascript"> function handler(json-data) { //对得到的json数据进行处理 } </script> <script src="http://example.com/request.php?callback=handler"></script>
PS: 参数名能够不叫callback,可是通常都叫这个。html
第二个script标签返回的内容会被当作JavaScript内容处理,因此服务器端能够这样写html5
<?php $callback = $_GET['callback']; // 得到回调函数 $data = array('a','b','c'); // 数据 echo $callback.'('.json_encode($data).')'; // 拼接输出 至关于输出JS:callback(json-data); ?>
这样就能处理数据了。java
jQuery能够这样写:json
<script type="text/javascript"> $.getJSON('http://example.com/request.php?callback=?', function(json-data) { //处理数据 }) </script>
2、利用Window.domainwindows
若是主页是http://www.example.com/a.html页面,iframe是http://example.com/b.html页面就会存在跨域问题:跨域
<script type="text/javascript"> function onLoad() { var iframe = document.getElementById('iframe'); var win = iframe.contentWindow; //这里可以获取到iframe的window对象,可是意义不大 var doc = win.document; //这里获取不到iframe的document对象 var doc = win.name; //一样获取不到windows对象的name ... } </script> <iframe src="http://example.com/b.html" onload="onLoad()" id="iframe"></iframe>
解决方法:服务器
咱们只要把http://www.example.com/a.html 和http://example.com/b.html这两个页面的document.domain都设成相同的域名就能够了。但要注意的是,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,由于主域已经不相同了。dom
主页脚本:
<script type="text/javascript"> function onLoad() { document.domain = 'example.com'; function test() { alert(document.getElementById('iframe').contentWindow); } } </script> <iframe src="http://example.com/b.html" onload="test()" id="iframe"></iframe>
iframe脚本:
<script type="text/javascript"> document.domain = 'example.com'; </script>
3、利用window.name || location.hash
演示window.name,给name赋的值必须是字符串,并且大小不能太大,最大2M左右。若是须要传其余的数据能够转换成JSON字符串。
<!-- a页面的脚本,3s后跳转到b页面 --> <script type="text/javascript"> window.name = '页面a设置的值'; setTimeout(function() { window.location = 'b.html'; }, 3000); </script> <!-- b页面的脚本 --> <script type="text/javascript"> alert(window.name); //获取到window.name 的值 </script>
利用这个特性,一样认为所请求的页面数据和主页数据不一样源:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>跨域</title> <script type="text/javascript"> function getData() { var iframe = document.getElementById('proxy'); iframe.onload = function() { var data = iframe.contentWindow.name;//iframe把数据放在了window.name里 alert(data); }; iframe.src = 'b.html';//不必定是b.html,只要和a.html同源便可,好比about:blank。这样iframe跳转到和a.html同源下,可是window.name没有发生改变,a.html就能够获取到! } </script> </head> <body> <!-- 不让iframe显现出来,iframe只是帮助跨域的 --> <iframe src="http://www.example.com/data.html" style="display: none;" onload="getData()" id="proxy"></iframe> </body> </html>
4、利用html5,postMessage()方法
<!-- http://test.com/a.html的代码 --> <script type="text/javascript"> function onLoad(){ var iframe = document.getElementById('iframe'); var win = iframe.contentWindow; win.postMessage('我是 a 页面'); } </script> <iframe src="http://www.test.com/b.html" id="iframe" onload="onLoad()"></iframe> <!-- http://www.test.com/b.html的代码 --> <script type="text/javascript"> window.onmessage = function(e) { e = e || event; alert(e.data); //也能够从iframe发到window }; </script>
<script type="text/javascript"> var img = new Image(); img.onload = img.onerror = function() { alert('OK'); }; //之因此能把onload和error写成同一个事件,由于这种跨域方式是单向的,只能从客户端向服务器端发送数据而客户端接受不到服务器端的数据 img.src = "http://www.example.com/test?name=kiscall"; </script>
7、Comet
Comet有两种实现方式,长轮询和流。
短轮询:
长轮询:
服务器实现流的方法:
<?php $i = 0; while(true) { echo "data"; flush(); sleep(10); $i++; } ?>
8、SSE和WebSockets就没时间介绍了!