怎樣才能使用AJax從服務器接收JS對象數據呢?你可以使用一種叫Javascript 對象符號的格式接收數據。本hack講述用戶輸入信息,從服務器得到JSON格式的響應數據。
JSON很普通而直觀,這也許是許多開發者喜歡使用的原因吧。一個例子就是,服務器程序從服務器得到信息,然後以JSON格式返回給web頁面。JSON格式的數據描述如下:
左大括號“{”
一個或多個屬性名,以冒號隔開的對應的值,以逗號隔開的屬性/值對。
右大括號 “}”
每個屬性的值可以是:
簡單的字符串,例如 “hello”
數組,例如 [1,2,3,4]
數字
true, false, 或 null
其他對象,組合的,或者對象中還有對象。
詳細信息請訪問:http://www.JSon.org
在JavaScript中,對象的格式是嚴格的。作為一個例子,在hack2中的請求信息改寫為JSON格式為:
{
firstname:“Bruce”,
lastname:“Perry”,
gender:“M”,
country:“USA”
}
Magic JSON
在這一部分裡,我們還使用hack2中的例子,只是處理的數據是JSON格式的數據。頁面的Html代碼如下:
“http://www.w3.org/TR/1999/REC-Html401–19991224/strict.dtd”>
當JS處理返回值的時候,需要注意XSS攻擊。這對於那些使用eval或其他相關函數來說是一個潛在的威脅。
作為一個相應的措施,在函數eval使用responseText之前,客戶端代碼可以過濾並檢測返回值(即,通過檢查XMLHttpRequest responseText屬性)
下面是hack的代碼,我們將著重關注處理返回值部分的代碼:
var request;
var queryString; //保存POSTed 數據
function sendData( ){
setQueryString( );
url=“http://www.parkerriver.com/s/JSon”;
httpRequest(“POST”,url,true);
}
//event handler for XMLHttpRequest
function handleJSon( ){
if(request.readyState == 4){
if(request.status == 200){
var resp = request.responseText;
var func = new Function(“return ”+resp);
var objt = func( );
var div = document.getElementById(“JSon”;
stylizeDiv(resp,div);
div = document.getElementById(“props”;
div.innerHtml=”
/* Initialize a request object that is already constructed */
function initReq(reqType,url,bool){
/* Specify the function that will handle the HTTP response */
request.onreadystatechange=handleJSon;
request.open(reqType,url,bool);
request.setRequestHeader(“Content-Type”,
“application/x-www-form-urlencoded; charset=UTF-8”;
request.send(queryString);
}
/* Wrapper function for constructing a request object.
Parameters:
reqType: The HTTP request type, such as GET or POST.
url: The URL of the server program.
asynch: Whether to send the request asynchronously or not. */
function httpRequest(reqType,url,asynch){
//Snipped… See Hack #1 or #2
}
function setQueryString( ){
queryString=“”;
var frm = document.forms[0];
var numberElements = frm.elements.length;
for(var i = 0; i < numberElements; i++){
if(i < numberElements-1){
queryString = frm.elements[i].name"="+
encodeURIComponent(frm.elements[i].value)+“&”;
} else {
queryString = frm.elements[i].name"="+
encodeURIComponent(frm.elements[i].value);
}
}
}
function stylizeDiv(bdyTxt,div){
//reset DIV content
div.innerHtml=“ ”;
div.style.fontSize=“1.2em”;
div.style.backgroundColor=“yellow”;
div.appendChild(document.createTextNode(bdyTxt));
}
如本章前面的hack介紹的,initReq( )函數初始化request對象並向服務器發送HTTP請求。
事件處理函數將調用handleJson。相應數據的格式是JSON格式的字符串,而不是其他的XML或其他格式的數據。JS將這些返回文本看作string對象。因此,代碼啟動open步驟,在服務器返回值被轉化成js對象之前。(btw,在本節裡,服務器在發送響應數據之前會將請求參數重新格式化成JSON格式。)
這裡沒有包括特定的錯誤處理代碼,而將其放在hack8中介紹。
在函數handleJson內的代碼(高亮顯示的部分),變量resp保存HTTP響應文本,JS將其看作string。令人感興趣的是函數的構造函數:
var func = new Function(“return ”+resp);
上面的代碼將創建一個新的函數對象,以變量func命名。JavaScript編程者應當明白,大多數函數需要在代碼中預先定義和聲明,或者作為函數字面量創建。然而,在本例中,我們需要使用一個字符串動態的定義一個函數體,並且函數的構造子能提供完美的工具。
Thanks to this site for guidance on this code usage: http://www.jibbering.com/2002/4/httprequest.Html.
另一種轉換JSON字符串的方法是:
var resp = request.responseText;var obj = eval( “(” resp ")" );
在使用eval和一個數組的時候,也可以不必使用圓括號:
var resp = request.responseText;//resp 保存的如 “[1,2,3,4]”
var arrObject = eval(resp);
接下來的行用來創建一個返回一個對象字面量的寒暑,來描述服務器返回值。然後可以調用函數並使用返回對象來使用DOM編程在web頁面動態顯示服務器的返回結果。
var objt = func( );
var div = document.getElementById(“JSon”;
stylizeDiv(resp,div);
div = document.getElementById(“props”;
div.innerHtml=”
objt變量來存儲對象字面量。變量可從對象中取得,形如objt.firstname。
Figure 1-10 shows what the web page looks like after it has received a response.
Figure 1-10. Visualizing JavaScript propertIEs is sweet!
在服務器端
Java servlet用來處理請求。作為對服務器端有更多的了解,下面是該servlet的doPost方法的代碼:
protected void doPost(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse) throws
ServletException, IOException {
Map valMap = httpServletRequest.getParameterMap( );
StringBuffer body = new StringBuffer(“{\\n”;
if(valMap != null) {
String val=null;
String key = null;
Map.Entry me = null;
Set entrIEs = valMap.entrySet( );
int size = entrIEs.size( );
int counter=0;
for(Iterator iter= entrIEs.iterator( );iter.hasNext( ) {
counter++;
me=(Map.Entry) iter.next( );
val= ((String[])me.getValue( ))[0];
key = (String) me.getKey( );
if(counter < size) {
body.append(key).append(“:\\““.append(val).append(“\\“,\\n”;
} else {
//remove comma for last entry
body.append(key).append(“:\\““.append(val).append(“\\“\\n”;
}
}
}
body.append(“}”;
AJaxUtil.sendText(httpServletResponse,body.toString( ));
}
AJaxUtil類發送HTTP響應以Content-Type of text/plain; charset=UTF-8的head。一些網站也有討論使用Content-Type,但是,在這裡,沒有固定的格式。
AJaxUtil 類設置了HTTP響應的頭格式:
response.setHeader("Cache-Control", "no-cache");