javascript中有同源策略,javascript存在跨域通訊的問題。典型例子如:Ajax沒法直接請求跨域的普通文件,存在跨域無權限訪問的問題。javascript
幾種常見的解決方法:php
1.JSONP 2. window.name+frame 3.document.domain + iframe 4.iframe+location.hash 5.HTML5 postMessage 方法html
1、JSONPjava
web頁面上只有<script><img><iframe>這些擁有「src」屬性的標籤是擁有跨域能力的。因此當前解決跨域的JSONP方案就是經過<script>的這一特性來實現的。web
原理:<script>標籤的src屬性是沒有跨域的限制的。因此JSONP動態建立一個<script>標籤,將本地方法名做爲請求參數傳遞給src屬性的url,服務器端獲取請求中該參數即客戶端的函數名,與要返回給庫戶端的json數據拼接成一個函數調用的javascript語句,返回給客戶端,客戶端獲取返回的javascript語句並執行,該javascript函數的入參即爲服務器端拼接的json數據,用這樣的方法來實如今客戶端來對異域服務器返回的請求數據進行處理。ajax
簡單歸納即,JSONP返回給客戶端一串javascript腳本的字符串,腳本中封裝json數據。因此這個就決定了JSONP必須在服務器端對返回數據進行處理,加上callback的函數名json
JSONP 的相關ajax方法 :跨域
1.getJSON(url+"?callback=?",data,success(data,status,xhr));瀏覽器
例:安全
(server.php能夠跨域放置,getJSON參數該爲響應的地址便可)
function handleclick()
{
$.getJSON("server.php?callback=?",function(data){
alert(data.weatherinfo.city+":"+data.weatherinfo.weather);
});
}
2.get(url+"?callback=?",data,success(data,status,xhr),"jsonp");
例:
function handleclick()
{
$.get("server.php?callback=?",function(data){
alert(data.weatherinfo.city+":"+data.weatherinfo.weather);
},"jsonp");
}
3.$.ajax
例:
$.ajax({
url:"server.php",
dataType:"jsonp",
jsonp:"callback",
type:"GET",
success:function(data){
alert(data.weatherinfo.city+":"+data.weatherinfo.weather);
}
error:function(xhr,errortext,error){
console.log("requset state:"+xhr.readyState+";errorText:"+errortext);
}
});
服務器端:
server.php
<?php
header("Content-Type:text/html;charset=utf-8");
header("Cache-Control:no-cache");
$callfunc=$_GET["callback"];
$content=file_get_contents("http://www.weather.com.cn/data/cityinfo/101190101.html");
echo $callfunc."(".$content.")";
?>
ajax 和 jsonp的本質區別是ajax是經過XMLHttpRequest來獲取非本頁內容,不能跨域,而jsonp是經過動態添加<script>標籤來獲取跨域服務器返回的腳本。
缺點:1.服務器端返回給客戶端javascript腳本會對客戶端產生不安全因素。
2.須要服務端配合傳輸相應格式數據。
3.不能解決不一樣域兩頁面之間進行javascript的調用問題。
2、HTML5 postMessage 方法
能夠用 iframe.postMessage(json,"*"); 來發送數據。
用onmessage方法來獲取跨域的數據
3、window.name + iframe
原理:name在瀏覽器環境中爲一個全局/window對象的屬性,且在frame中加載新頁面時,name的屬性值依舊保持不變。
則能夠先讓iframe加載跨域頁面,經過window.name屬性跨域傳輸數據,因爲同源策略window.name不能訪問,因此只要將iframe從新連接到本域頁面,而後就能夠訪問window.name中的數據。
例:a.html:
<script>
var status=0;
var data;
var fr=document.createElement("iframe");
function frload(){
if(status == 1)
{
data=fr.contentWindow.name;
alert(data);
destroyfr(fr);
}
else if(status == 0)
{
status=1;
fr.contentWindow.location.href="proxy.html"
}
};
fr.src="http://xxx.com/b.html";
fr.style.display="none";
if(fr.attachEvent){
fr.attachEvent('onload',frload);
}else
{
fr.onload=frload;
}
function destroyfr(ifr)
{
ifr.src='about:blank';
try{
ifr.contentWindow.document.write('');
ifr.contentWindow.document.clear();
}catch(e){}
ifr.parentNode.removeChild(ifr);
}
document.body.appendChild(fr);
</script>
本域代理頁面爲proxy.html,(也能夠直接設置一個空白頁面about:blank)
跨域頁面:b.html:
<script>
window.name='{"name":"roy","age":"20"}';
</script>
4、document.domain + iframe
原理:針對主域相同而子域不一樣的兩個頁面,能夠經過設置document.domain=「主域」 來解決。
將 http://www.f.com/a.html 和 http://m.f.com/b.html 都設置document.domain="f.com",而後在a.html中經過iframe加載b.html,則a.html 頁面能夠經過iframe.contentDocument.getElementById("id"); 來獲取b頁面數據。
5、iframe+location.hash
原理:改變頁面hash不會致使頁面刷新,因此經過添加或改變iframe的src連接的hash值來進行跨域傳遞數據
a頁面建立iframe跨域請求b頁面,請求參數置於hash中,b頁面從location.hash中獲取請求參數生成響應數據,a 和b跨域因此b頁面中沒法經過parent對象改變a頁面的loaction.hash的值。因此須要在b.html中動態建立iframe加載一個和a同域的c頁面,將響應數據置於c的loaction.hash中,而後在c頁面中則能夠經過parent.parent來訪問a頁面並經過loaction.hash來傳遞遠程頁面的返回值
缺點:數據大小有限,而且數據直接暴露在url中