什么是跨域?
說跨域之前先要談幾個(gè)概念。跨域問題要從同源策略談起,那什么是同源策略呢?
同源是下面三項(xiàng)都相同,缺一不可
協(xié)議+域名+端口
如果不同源,只可以引用css、js、php等文件,但不可以讀寫這些資源,這就是同源策略最通俗的描述。
看個(gè)瀏覽器報(bào)錯(cuò)例子:
我利用SAE同一項(xiàng)目下的兩個(gè)域名http://1.georgema.applinzi. com
和http://2.georgema.applinzi.com
(注意這兩個(gè)域名是不同源的)發(fā)送ajax
請求,在瀏覽器中可以看到報(bào)錯(cuò)。
同源策略限制報(bào)錯(cuò)
如果我們要打破這個(gè)限制就需要跨域。
實(shí)現(xiàn)跨域有很多種方法,下面介紹幾種:
跨域方法
第一種:降域
降域通俗地講就是把域名變成符合同源的。
-
document.domain
的設(shè)置規(guī)則:- 只能設(shè)置為比它更高級的域名,www.a.first.com的
document.domain
可設(shè)置為 a.first.com ,也可以是 first.com ,但不可以是 google.com - 假設(shè)www.a.first.com的
document.domain
被設(shè)置為 first.com 就不能再向下重新設(shè)置為 a.first.com
- 只能設(shè)置為比它更高級的域名,www.a.first.com的
//以2.georgema.applinzi.com為例
<body>
<iframe src='//1.georgema.applinzi.com/'></iframe>
<h1>
跨域測試
</h1>
<script>
//這里的domain只能設(shè)置為上級的域名
document.domain='georgema.applinzi.com';
var ifr=window.frames;
ifr.onload=function(){
// to do...
}
</script>
</body>
//同時(shí)1.georgema.applinzi.com中也要設(shè)置domain
<script>
document.domain='georgema.applinzi.com';
function(){
//to do...
};
</script>
- 這種方法的局限性很大,一般只用來解決不同
iframe
之間的通信 - 降域之后上級域名下所有子域的安全性受到威脅
第二種:JSONP
- 這種方法利用的是瀏覽器允許
script
跨域 - 動(dòng)態(tài)添加的
script
中加入json格式數(shù)據(jù),實(shí)現(xiàn)數(shù)據(jù)讀寫
先看怎么實(shí)現(xiàn)動(dòng)態(tài)script
//在2.georgema.applinzi.com里讀取www.1.georgema.applinzi.com/user.js傳回的json數(shù)據(jù)
var script = document.createElement('script');
window.getUsername = function(data){
var p = document.createElement('p');
p.innerText='username: '+data.name;
document.body.appendChild(p);
}
script.src="http://1.georgema.applinzi.com/user.js?callback='getUsername''";
document.body.appendChild(script);
//www.1.georgema.applinzi.com/user.js中的json
getUsername({
'name': 'Nicholas'
})
發(fā)送ajax得到j(luò)son數(shù)據(jù)(和上面方法是一樣的,都是利用get請求返回json數(shù)據(jù))就是 JSONP方法了
$.ajax({
url:'//1.georgema.applinzi.com/user.js',
dataType:'jsonp',
jsonpCallback:'getUsername',
success:function(){
onSuccess();
}
error:function(){
onError();
}
});
function getUsername(data){
var p = document.createElement('p');
p.innerText='username: '+data.name;
document.body.appendChild(p);
}
function onError(){
alert('連接出錯(cuò)');
}
- 這種方法的缺點(diǎn):
- 容易被注入惡意代碼,解決方案是服務(wù)器端加入字符串過濾
- 一般需要token驗(yàn)證,不讓第三方訪問
- 只能發(fā)送
GET
請求
第三種:CORS方法
CORS方法是在服務(wù)器對接受的來源域進(jìn)行設(shè)置。Access-Control-Allow-Origin
可以指定接受請求的具體域名,也可也設(shè)置為*
表示所有源的請求都可以
//CORS方法,2.georgema.applinzi.com發(fā)送post請求
$.ajax({
url:'//1.georgema.applinzi.com/test.php',
type:'POST',
data:'georgema',
error:function(){
alert('連接錯(cuò)誤!');
},
success:function(res){
alert(res);
}
});
//1.georgema.applinzi.com/test.php
<?php
header('Access-Control-Allow-Origin:http://2.georgema.applinzi.com'); //加這一句可以接收指定源的請求
echo 'hello';
?>
0_1466859081679_cors.png
0_1466859102371_cors2.png
- 這種方法的缺點(diǎn):
- 現(xiàn)代瀏覽器支持比較好,老版本瀏覽器不支持
- 需要后端支持
以上內(nèi)容參考饑人谷教程