新手在練習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就沒時間介紹了!