第3章 与服务器通信:发送请求和处理响应
3.1 处理服务器响应
XMLHttpRequest对象提供了两个可以用来访问服务器响应的属性:responseText,responseXML。
3.1.1 使用innerHTML属性创建动态内容
innerHTML属性是一个非标准的属性,最早在IE中实现,后来也为其他许多流行的浏览器采用。这是一个简单的串,表示一组开始标记和结束标记之间的内容。
innerHTML.html
-----------------
<head>
<script type="text/javascript">
var xmlHttp;
function createXMLHttpRequest() {
if (window.ActiveXObject) {
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
else if (window.XMLHttpRequest) {
xmlHttp = new XMLHttpRequest();
}
}
function startRequest() {
createXMLHttpRequest();
xmlHttp.onreadystatechange = handleStateChange;
xmlHttp.open("GET", "innerHTML.xml", true);
xmlHttp.send(null);
}
function handleStateChange() {
if (xmlHttp.readyState == 4) {
if (xmlHttp.status == 200) {
document.getElementById("results").innerHTML = xmlHttp.responseText;
}
}
}
</script>
</head>
<body>
<form action="#">
<input type="button" value="search for today's Activities" οnclick="startRequest();"/>
</form>
<div id="results"></div>
</body>
innerHTML.xml
-----------------
<table border="1">
<tbody>
<tr>
<th>Activity Name</th>
<th>Location</th>
<th>Time</th>
</tr>
<tr>
<td>Waterskiing</td>
<td>Dock #1</td>
<td>9:00 AM</td>
</tr>
<tr>
<td>Volleyball</td>
<td>East Court</td>
<td>2:00 PM</td>
</tr>
</tbody>
</table>
3.1.2 将响应解析为XML
文档对象模型(DOM)是与平台和语言无关的接口,允许程序和脚本动态地访问和更新文档的内容、结构和样式。文档可以进一步处理,处理的结果可以放回到所提供的页面中。
DOM是面向HTML和XML文档的API,为文档提供了结构化表示,并定义了如何通过脚本来访问文档结构。JavaScript是用于访问和处理DOM的语言。
用于处理XML文档的DOM元素属性:childNodes, firstChild, lastChild, nextSibling, nodeValue, parentNode, previousSibling。
用于遍历XML文档的DOM元素方法:getElementById(), getElementsByTagName(), hasChileNodes(), getAttribute()。
var xmlHttp;
var requestType = "";
function handleStateChange() {
if (xmlHttp.readyState == 4) {
if (requestType == "north") {
listNorthStates();
}
else if (requestType == "all") {
listAllStates();
}
}
}
function listNorthStates() {
var xmlDoc = xmlHttp.responseXML;
var northNode = xmlDoc.getElementsByTagName("north")[0];
var out = "Norther States";
var northStates = northNode.getElementsByTagName("state");
outputList("Northern States", northStates);
}
function listAllStates() {
var xmlDoc = xmlHttp.responseXML;
var allStates = xmlDoc.getElementsByTagName("state");
outputList("All States", allStates);
}
function outputList(title, states) {
var out = title;
var currentState = null;
for (var i = 0; i < states.length; i++) {
currentState = states[i];
out = out + "/n- " + currentState.childNodes[0].nodeValue;
}
alert(out);
}
3.1.3 使用W3C DOM动态编辑页面
动态创建内容时所使用的W3C DOM属性和方法:
document.createElement(tagName)
document.createTextNode(text)
<element>.appendChild(childNode)
<element>.getAttribute(name)
<element>.setAttribute(name, value)
<element>.insertBefore(newNode, targetNode)
<element>.removeAttribute(name)
<element>.removeChild(childNode)
<element>.replaceChild(newNode, oldNode)
<element>.hasChildnodes()
dynamicContent.xml
-------------------
<properties>
<property>
<address>...</address>
<price>$1000</price>
<comments>....</comments>
</property>
....
</properties>
dynamicContent.html
---------------------
<body>
<form action="#">
Show listings from
<select>
<option value="50">$50</option>
<option value="100">$100</option>
</select>
to
<select>
<option value="100">$100</option>
<option value="200">$200</option>
</select>
<input type="button" value="search" οnclick="doSearch();"/>
</form>
<span id="header">
</span>
<table id="resultsTable" width="75%" border="0">
<tbody id="resultsBody">
</tbody>
</table>
</body>
function doSearch() {...}
function handleStateChange() {...}
function clearPreviousResults() {
var header = document.getElementById("header");
if (header.hasChildNodes()) {
header.removeChild(header.childNodes[0]);
}
var tableBody = document.getElementById("resultsBody");
while (tableBody.childNodes.length > 0) {
tableBody.removeChild(tableBody.childNodes[0]);
}
}
function parseResults() {
var results = xmlHttp.responseXML;
var property = null, address = "", price = "", comments = "";
var properties = results.getElementsByTagName("property");
for (var i = 0; i < properties.length; i++) {
property = properties[i];
address = property.getElementsByTagName("address")[0].firstChild.nodeValue;
price = property.getElementsByTagName("price")[0].firstChild.nodeValue;
comments = property.getElementsByTagName("comments")[0].firstChild.nodeValue;
addTableRow(address, price, comments);
}
var header = document.createElement("h2");
var headerText = document.createTextNode("Results:");
header.appendChild(headerText);
document.getElementById("header").appendChild(header);
document.getElementById("resultTable").setAttribute("boder", "1");
}
function addTableRow(address, price, comments) {
var row = document.createElement("tr");
var cell = createCellWithText(address);
row.appendChild(cell);
...
}
function createCellWithText(text) {
var cell = document.createElement("td");
var textNode = document.createTextNode(text);
cell.appendChild(textNode);
return cell;
}
3.2 发送请求参数
function createQueryString() {
var firstName = document.getElementById("firstName").value;
var birthday = document.getElementById("birthday".value;
var queryString = "firstName=" + firstName + "&birthday=" + birthday;
return queryString;
}
function doRequestUsingGET() {
createXMLHttpRequest();
var queryString = "GetAndPostExample?";
queryString += createQueryString() + "&timeStamp=" + new Date().getTime();
xmlHttp.onreadystatechange = handleStateChange;
xmlHttp.open("GET", queryString, true);
xmlHttp.send(null);
}
function doRequestUsingPOST() {
createXMLHttpRequest();
var url = "GetAndPostExample?timeStamp=" + new Date().getTime();
var queryString = createQueryString();
xmlHttp.open("POST", url, true);
xmlHttp.onreadystatechange = handleStateChange;
xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;");
xmlHttp.send(queryString);
}
服务器端的处理:
public class GetAndPostExample extends HttpServlet {
protected void processRequest(HttpServletRequest request, HttpServletResponse response, String method)
{
response.setContentType("text/xml");
String firstName = request.getParameter("firstname");
String birthday = request.getParameter("birthday");
String responseText = "Hello " + firstName + " " + "Your birthday is " + birthday);
PrintWriter out = response.getWriter();
out.println(responseText);
out.close();
}
protected void doGet()
{processRequest(request, response, "GET");}
protected void doPost()
{processRequest(request, response, "POST");}
}
3.2.1 请求参数作为XML发送
可以把XML作为请求体的一部分发送到服务器,这与POST请求中将查询串作为请求体的一部分进行发送异曲同工。服务器可以从请求体读取XML,并加以处理。
function createXML() {
var xml = "<pets>";
var options = document.getElementById("petTypes").childNodes;
var option = null;
for (var i = 0; i < options.length; i++) {
option = options[i];
if (option.selected) {
xml = xml + "<type>" + option.value + "<//type>";
}
}
xml = xml + "<//pets>";
return xml;
}
function sendPetTypes() {
createXMLHttpRequest();
var xml = createXML();
var url = "PostingXMLExample?timeStamp=" + new Date().getTime();
xmlHttp.open("POST", url, true);
xmlHttp.onreadystatechange = handleStateChange;
xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlHttp.send(xml);
}
3.3.2 使用JSON向服务器发送数据
JSON是一种文本格式,独立于具体一语言,建立在两种数据结构基础上:名/值对集合,值的有序表。
function Car(make, model, year, color) {
this.make = make;
this.model = model;
this.year = year;
this.color = color;
}
function getCarObject() {
return new Car("Dodge", "Coronet R/T", 1968, "yelloe");
}
function doJSON() {
var car = getCarObject();
//Use JSON JavaScript library to stringify the Car object
var carAsJSON = JSON.stringify(car);
......
xmlHttp.send(carAsJSON);
}
服务器端:
String json = readJSONStringFromRequestBody(request);
//Use the JSON-Java binding library to create a JSON object in Java
JSONObject jsonObject = null;
jsonObject = new JSONObject(json)
var color = jsonObject.getString("color");
private String readJSONStringFromRequestBody(HttpServletRequest request) {
StringBuffer json = new StringBuffer();
String line = null;
BufferedReader reader = request.getReader();
while((line = reader.readLine()) != null) {
json.append(line);
}
return json.toString();
}
3.3 小结