一、首先我們要明白跨域的字面概念,讀過留過印象之后,下面將會有例子進一步解釋
有一篇文章《跨域的理解與實現》描述得很清楚,在這里摘錄如下: 域(Domain)是Windows網絡中獨立運行的單位,域之間相互訪問則需要建立信任關系(即Trust Relation)。信任關系是連接在域與域之間的橋梁。當一個域與其他域建立了信任關系后,2個域之間不但可以按需要相互進行管理,還可以跨網分配文件和打印機等設備資源,使不同的域之間實現網絡資源的共享與管理。
簡單的說就是A網站的javascript代碼試圖訪問B網站,包括提交內容和獲取內容,但由於安全原因,跨域訪問是被各大瀏覽器所默認禁止的。
但怎么樣才算跨域呢?這里舉了幾個例子(什么是跨域,什么是不算跨域)
http://www.a.com/a.js與http://www.a.com/b.js同一域名下允許
http://www.a.com/lab/a.js與http://www.a.com/script/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同一域名,不同二級域名(同上)不允許(cookie這種情況下也不允許訪問)
http://www.cnblogs.com/a.js與http://www.a.com/b.js不同域名不允許
二、明白了跨域是什么之后,下面一一舉出解決跨域的各種辦法。
總的來說共有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);
