1、首先咱們要明白跨域的字面概念,讀過留過印象以後,下面將會有例子進一步解釋javascript
有一篇文章《跨域的理解與實現》描述得很清楚,在這裏摘錄以下: 域(Domain)是Windows網絡中獨立運行的單位,域之間相互訪問則須要創建信任關係(即Trust Relation)。信任關係是鏈接在域與域之間的橋樑。當一個域與其餘域創建了信任關係後,2個域之間不但能夠按須要相互進行管理,還能夠跨網分配文件和打印機等設備資源,使不一樣的域之間實現網絡資源的共享與管理。html
簡單的說就是A網站的javascript代碼試圖訪問B網站,包括提交內容和獲取內容,但因爲安全緣由,跨域訪問是被各大瀏覽器所默認禁止的。前端
但怎麼樣纔算跨域呢?這裏舉了幾個例子(什麼是跨域,什麼是不算跨域)java
http://www.a.com/a.js與http://www.a.com/b.js同一域名下容許angularjs
http://www.a.com/lab/a.js與http://www.a.com/script/b.js同一域名下不一樣文件夾容許ajax
http://www.a.com:8000/a.js與http://www.a.com/b.js同一域名,不一樣端口不容許json
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同一域名,不一樣二級域名(同上)不容許(cookie這種狀況下也不容許訪問)
http://www.cnblogs.com/a.js與http://www.a.com/b.js不一樣域名不容許
2、明白了跨域是什麼以後,下面一一舉出解決跨域的各類辦法。
總的來講共有2種方法,
1.jsonp方式(其中jsonp方式能夠用原生js,ajax,angular.js均可以實現)
實現以前,先理解下jsonp是什麼?
爲了便於客戶端使用數據,逐漸造成了一種非正式傳輸協議,人們把它稱做JSONP,該協議的一個要點就是容許用戶傳遞一個callback參數給服務端,而後服務端返回數據時會將這個callback參數做爲函數名來包裹住JSON數據,這樣客戶端就能夠隨意定製本身的函數來自動處理返回數據了。具體理解看代碼:
<script> function getData(){ var script = document.createElement('script'); script.type = 'text/javascript'; // 同源策略不阻止將動態腳本元素插入文檔中因此腳本元素是能夠跨域訪問的,因此這裏用到原生js,其中callbackFunc實際上是個方法,因此咱們寫回調方法名字要跟這個一致
var myUrl = 'http://c.m.163.com/nc/article/headline/T1348647853363/0-10.html'; script.src = 'http://localhost:8000/?myUrl=' + myUrl + '&callback=callbackFunc'; document.getElementsByTagName('head')[0].appendChild(script); } function callbackFunc(data){ console.log(data); } </script>
下面看服務端的配合,上面代碼中說了callback後跟的是一個函數是和後臺約定好的函數,那麼後臺須要把jsonp數據包裹在整個函數裏,而後返回處理後的數據,這樣就完成了前端和後臺的jsonp協議,實現了跨域請求
上面代碼中有提到同源策略,這裏補充一下。同源策略就是阻止從一個域上加載的腳本獲取或操做另外一個域上的文檔屬性(不阻止將動態腳本元素插入文檔中因此腳本元素是能夠跨域訪問的)。
var http = require('http'); var url = require('url'); var qs = require('querystring'); http.createServer(function(req,res){ //建立一個結果對象,用來裝載數據 var resultData = ''; //取出網址後面的參數 var query = url.parse(req.url).query; console.log(query); //先將字符串轉化爲對象 var qs_parse = qs.parse(query); console.log(qs_parse); //再將muUrl參數當作路徑發送請求 http.get(qs_parse.myUrl,function(request){ request.setEncoding('utf-8'); request.on('data',function(result){ resultData += result; }); request.on('end',function(){ console.log(resultData);
var str = qs_parse.callback + '(' + JSON.stringify(resultData) + ')'; res.end(str); }); }).on('error',function(error){ console.log(error); }); }).listen(8000); console.log('server is running at 8000');
看ajax實現代碼(服務器代碼同上):
<script> function getData(){ var myUrl = 'http://c.m.163.com/nc/article/headline/T1348647853363/0-10.html'; var url = 'http://localhost:8000/?myUrl=' + myUrl; //ajax會給咱們生成那個callback $.ajax({ /*** * 請求路徑 * 請求方法 * 傳輸協議 * 成功、失敗回調函數 */ url:url, type:'get', dataType:'jsonp', success:function(result){ console.log(JSON.parse(result)); }, error:function(e){ console.log(e); } }); } </script>
看angular.js實現方法(服務器同上代碼同上):
angular.module('myApp',[]) .controller('myController',['$scope','$http',function($scope,$http){ $scope.getData = function(){ var myUrl = 'http://c.m.163.com/nc/article/headline/T1348647853363/0-10.html'; $http({ method:'jsonp', url:'http://localhost:8000/?myUrl=' + myUrl + '&callback=JSON_CALLBACK' //這裏的callback是angular自動生成的,JSON_CALLBACK表明着自動生成的回調函數名 }).then( function success(result){ console.log(result); },function error(e){ console.log(e); }); } }]);
2.post設置請求頭的方式,angularjs內置封裝了類ajax的網絡服務$http,從而實現了不依賴外部插件來完成完整的先後端分離方案。
angular.module('myApp',[]).controller('myController',['$scope','$http',function($scope,$http){ $scope.getData = function(){ $http({ method:'POST', headers:{ //在請求的時候設置請求頭,固然請求有不少種,咱們以這種爲例 'content-type':'application/x-www-form-urlencoded' }, url:'http://localhost:8000', data:{ //字符串或者對象,這個對象包含了請求體的全部內容,會被髮送給服務器 myUrl:'http://c.m.163.com/nc/article/headline/T1348647853363/0-10.html' } }).then(function success(result){ console.log(result); },function error(error){ console.log(error); }); } }]);
由於是post請求方式,服務器端代碼也須要改動:(設置爲*表明任意,這樣前端和後臺配合就完成了post請求的跨域操做、)
var http = require('http'); var url = require('url'); http.createServer(function(req,res){ //設置編碼格式 req.setEncoding('utf-8'); //設置響應頭,表示任意匹配,
res.setHeader('Access-Control-Allow-Origin','*'); var postData = ''; req.addListener('data',function(chunk){ postData += chunk; }); req.on('end',function(){ console.log('接受成功'); var myUrl = JSON.parse(postData).myUrl; console.log(myUrl); var result = ''; http.get(myUrl,function(request){ request.setEncoding('utf-8'); request.on('data',function(chunk){ result += chunk; }); request.on('end',function(){ res.end(result); }) }).on('error',function(error){ console.log(error); }); }); }).listen(8000);