一、出現原因
跨域是指a頁面想獲取b頁面資源,如果a、b頁面的協議、域名、端口、子域名不同,或是a頁面為ip地址,b頁面為域名地址,所進行的訪問行動都是跨域的,而瀏覽器為了安全問題一般都限制了跨域訪問,也就是不允許跨域請求資源。
例如:
URL | 說明 | 是否跨域 |
http://www.a.com/lab/a.js http://www.a.com/script/b.js |
同域名下不同文件 | 否 |
http://www.cnblogs.com/a.js http://www.a.com/b.js |
不同域名 | 是 |
http://www.a.com:8000/a.js http://www.a.com/b.js |
同域名下不同端口 | 是 |
http://www.a.com/a.js https://www.a.com/b.js |
同域名 不同協議 | 是 |
http://www.a.com/a.js http://70.32.92.74/b.js |
域名和域名對應ip | 是 |
http://www.a.com/a.js http://script.a.com/b.js |
主域名相同 子域名不同 | 是 |
http://www.a.com/a.js http://a.com/b.js |
同一域名,不同二級域名(同上) | 是 |
二、解決方案
【策略一】:Jsonp:需要目標服務器配合一個callback函數
JSONP(JSON with Padding)是一個非官方的協議,它允許在服務器端集成Script tags返回至客戶端,通過javascript callback的形式實現跨域訪問(這僅僅是JSONP簡單的實現形式)。
Json+padding(內填充),顧名思義,就是把JSON填充到一個盒子里,它的基本思想是,網頁通過添加一個<script>元素,向服務器請求JSON數據,這種做法不受同源政策限制;服務器收到請求后,將數據放在一個指定名字的回調函數里傳回來。
首先,網頁動態插入<script>元素,由它向跨源網址發出請求。
JSONP的產生:
1.AJAX直接請求普通文件存在跨域無權限訪問的問題,不管是靜態頁面也好.
2.不過我們在調用js文件的時候又不受跨域影響,比如引入jquery框架的,或者是調用相片的時候
3.凡是擁有scr這個屬性的標簽都可以跨域例如<script><img><iframe>
4.如果想通過純web端跨域訪問數據只有一種可能,那就是把遠程服務器上的數據裝進js格式的文件里.
5.而json又是一個輕量級的數據格式,還被js原生支持
6.為了便於客戶端使用數據,逐漸形成了一種非正式傳輸協議,人們把它稱作JSONP,該協議的一個要點就是允許用戶傳遞一個callback 參數給服務端
Js 客戶端 方案一:
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" /> <script type="text/javascript"> function jsonpCallback(result) { //alert(result); for(var i in result) { alert(i+":"+result[i]);//循環輸出a:1,b:2,etc. } } var JSONP=document.createElement("script"); JSONP.type="text/javascript"; JSONP.src="http://crossdomain.com/services.php?callback=jsonpCallback"; document.getElementsByTagName("head")[0].appendChild(JSONP); </script>
Js 客戶端 方案二:
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" /> <script type="text/javascript"> function jsonpCallback(result) { alert(result.a); alert(result.b); alert(result.c); for(var i in result) { alert(i+":"+result[i]);//循環輸出a:1,b:2,etc. } } </script> <script type="text/javascript" src="http://crossdomain.com/services.php?callback=jsonpCallback"></script>
Jquery 客戶端 方案一:
<script type="text/javascript" src="jquery.js"></script> <script type="text/javascript"> $.getJSON("http://crossdomain.com/services.php?callback=?", function(result) { for(var i in result) { alert(i+":"+result[i]);//循環輸出a:1,b:2,etc. } }); </script>
Jquery 客戶端 方案二:
<script type="text/javascript" src="jquery.js"></script> <script type="text/javascript"> $.ajax({ url:"http://crossdomain.com/services.php", type:'get',//注意:跨域請求是只能是get請求不能使用post請求 dataType:'jsonp', data:'', jsonp:'callback',//傳遞給請求處理程序或頁面的,用以獲得jsonp回調函數名的參數名(默認為:callback) jsonpCallback:"success",//自定義的jsonp回調函數名稱,默認為jQuery自動生成的隨機函數名 success:function(result) { console.log(result); }, timeout:3000 }); </script>
Jquery 客戶端 方案三:
<script type="text/javascript" src="jquery.js"></script> <script type="text/javascript"> $.get('http://crossdomain.com/services.php?callback=?', {name: encodeURIComponent('tester')}, function (json) { for(var i in json) alert(i+":"+json[i]); }, 'jsonp'); </script>
PHP 服務端:
//服務端返回JSON數據 $arr=array('a'=>1,'b'=>2,'c'=>3,'d'=>4,'e'=>5); $result=json_encode($arr); //動態執行回調函數 $callback=$_GET['callback']; echo $callback."($result)";
【策略二】基於iframe實現的跨子域:通過修改document.domain來跨子域
將子域和主域的document.domain設為同一個主域.前提條件:這兩個域名必須屬於同一個基礎域名!而且所用的協議,端口都要一致,否則無法利用document.domain進行跨域
主域相同的使用document.domain
【策略三】PHP設置header頭來實現跨域
//Access-Control-Allow-Origin:指定允許其他域名訪問。該字段是必須的。它的值要么是請求時Origin字段的值,要么是一個*,表示接受任意域名的請求。 header('Access-Control-Allow-Origin:*'); //Access-Control-Allow-Methods:響應類型 header('Access-Control-Allow-Methods:GET, POST, PUT, DELETE, OPTIONS'); //Access-Control-Allow-Headers:響應頭設置 header('Access-Control-Allow-Headers:X-Requested-With,Content-Type'); //Access-Control-Expose-Headers:該字段可選。CORS請求時,XMLHttpRequest對象的getResponseHeader()方法只能拿到6個基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必須在Access-Control-Expose-Headers里面指定。 header('Access-Control-Expose-Headers:Authorization');