js下跨域的問題很讓人頭疼,本文討論如何在javascript下實現跨域訪問,以及如何利用jquery來實現跨域訪問。
1,javascript下的跨域訪問
1)實現基本原理
在html的DOM節點中,<script>節點是可以訪問跨域服務器上的數據的,因此可以通過指定<script>的src屬性值為跨域的服務器的url,從而實現跨域訪問。
但是這個url的返回值不能是單純的諸如{id:1, name: 'shyman', age: 18, male:true}格式的json對象
設想一下,假如有一個名為example.js的javascript文件,該javascript里面的內容是{id:1, name: 'shyman', age: 18, male:true},
當我們通過<script type="text/javascript" src="example.js"></script>去引用這個javascript的時候,可以說這個被引用的js沒有任何一點作用,或者說我們根本訪問不到js里面的內容。
怎么辦??
於是,於是。。 如果上面的example.js里面的內容是var json = {id:1, name: 'shyman', age: 18, male:true}; callback(json);
或者是callback({id:1, name: 'shyman', age: 18, male:true});這樣的js才有意義嘛,這才是一個正常的js嘛。。
注意上面這種數據格式,它在json的外面添加了一個函數callback,我們稱這種數據格式為jsonp、或者json-p,翻譯起來就是"填充了的json"(json with padding) ,這種叫法我們暫時可以不管。
現在我們正常的引用了example.js,有一個問題,js中的callback這個方法我們並沒有定義,如果只引用這個js的話,瀏覽器肯定會提示腳本錯誤。
為了讓瀏覽器不報腳本錯誤,同時也為了執行這個callback方法,在引入example.js腳本之前,我們要在另一個js中對callback方法進行定義,比如
{
var ret = "";
for ( var pro in data)
ret += pro + ":" + data[pro] + "\n";
alert(ret);
}
這個時候在頁面剛打開的時候,會彈出從服務器上取回的jsonp數據中的json數據信息。
這樣一個簡單的js跨域就實現了。。
對了,對了。。還有剛開始提到的"<script>的src屬性值為跨域的服務器的url",這個跨域的url返回值如何構造呢,以servlet服務為例。
在servlet的get和post方法中如下方式構造返回字符串就可以了
2)改進實現
如上1)所述,其實已經實現了基本的js跨域,在實際應用中,不可能像1)那樣頁面一加載完,就立即去跨域的服務器取jsonp數據,而是需要調用的時候去取。
其實很簡單,首先定義callback方法(當然也可以是其他名字的方法,如xxx方法),然后動態地創建一個<script>元素,指定其url(該url返回值必須是由callback或xxx填充json的jsonp格式數據),並且動態地加入到<head>節點下。ok,就這么簡單
< head >
< meta http-equiv ="Content-Type" content ="text/html;charset=gb2312" >
< title >javascript crossdomain </ title >
< script type ="text/javascript" >
var script = document.createElement( " script " );
script.type = " text/javascript " ;
var uid;
var url = " http://localhost:8080/xtgeomaps_app/CrossDomain " ;
var jsonpCallback = " xxx " ;
function query()
{
uid = document.getElementById("us erid " ).value;
doQuery(uid, url, jsonpCallback);
}
function doQuery(_uid, _url, _jsonpCallback)
{
script.src = _url + " ?_uid= " + _uid + " &_jsonpCallback= " + _jsonpCallback; // 返回字符串xxx({id:1, name: 'shyman', age: 18, male:true});
var head = document.head || document.getElementsByTagName( " head " )[ 0 ] || document.documentElement;
if ( head && script.parentNode ) {
head.removeChild( script );
}
head.insertBefore( script, head.firstChild );
}
function xxx(data)
{
var ret = "" ;
for ( var pro in data)
ret += pro + " : " + data[pro] + " \n " ;
alert(ret);
}
</ script >
</ head >
< body >
輸入要查詢的id: < input id ="userid" />< br />< br />
< input type ="button" value ="javascript跨域訪問" onclick ="query(uid, url, jsonpCallback)" />
</ body >
</ html >
跨域服務器servlet的代碼為
String uid = request.getParameter("_uid");
String jsonpCallback = request.getParameter("_jsonpCallback");
response.getWriter().write(jsonpCallback + "({id:" + uid + ", name: 'shyman', age: 18, male:true});"); // 構造javascript的執行函數字符串
}
js的跨域就搞定了
2,jquery跨域實現
其實上面js跨域的實現借鑒了jquery的實現方法,實現方法如下
< meta http-equiv ="Content-Type" content ="text/html;charset=gb2312" >
< title >jquery crossdomain </ title >
< script type ="text/javascript" src ="jquery-1.7.2.min.js" ></ script >
< script type ="text/javascript" >
function query()
{
var uid = $("#userid").val();
url: ' http://localhost:8080/xtgeomaps_app/CrossDomain ' ,
data: {_uid: uid},
dataType: ' jsonp ' ,
jsonp: " _jsonpCallback " ,
// jsonpCallback: "xxx",
success: function (json) { // json={id:1, name: 'shyman', age: 18, male:true}
var ret = "" ;
for ( var pro in json)
ret += pro + " : " + json[pro] + " \n " ;
alert(ret);
},
error: function (jqXHR, textStatus, errorThrown){
alert(textStatus);
}
});
}
</ script >
</ head >
< body >
輸入要查詢的id: < input id ="userid" />< br />< br />
< input type ="button" value ="jquery跨域訪問" onclick ="query()" />
</ body >
</ html >
跨域服務器端代碼同1中的代碼
總結一下吧,所謂js跨域,並不是所有的域都能跨,如果跨域服務器返回的不是jsonp數據格式,基本很難通過js跨域。
js跨域實現不了,怎么辦?呵呵,那就只能通過自己寫代理的方式了