第一部分:AJAX入门
1 Ajax 尝试建立桌面应用程序的功能和交互性,与不断更新的 Web 应用程序之间的桥梁。可以使用像桌面应用 程序中常见的动态用户界面和漂亮的控件,不过是在 Web 应用程序中。
2 下面是 Ajax 应用程序所用到的基本技术:
- HTML 用于建立 Web 表单并确定应用程序其他部分使用的字段。
- JavaScript 代码是运行 Ajax 应用程序的核心代码,帮助改进与服务器应用程序的通信。
- DHTML 或 Dynamic HTML,用于动态更新表单。我们将使用
div
、span
和其他动态 HTML 元素来标记 HTML。 - 文档对象模型 DOM 用于(通过 JavaScript 代码)处理 HTML 结构和(某些情况下)服务器返回的 XML。
Ajax 基本上就是把 JavaScript 技术和 XMLHttpRequest
对象放在 Web 表单和服务器之间。当用户填写表单时,数据发送给一些 JavaScript 代码而不是 直接发送给服务器。相反,JavaScript 代码捕获表单数据并向服务器发送请求。同时用户屏幕上的表单也不会闪烁、消失或延迟。换句话说,JavaScript 代码在幕后发送请求,用户甚至不知道请求的发出。更好的是,请求是异步发送的,就是说 JavaScript 代码(和用户)不用等待服务器的响应。因此用户可以继续输入数据、滚动屏幕和使用应用程序。
然后,服务器 将数据返回 JavaScript 代码(仍然在 Web 表单中),后者决定如何处理这些数据。它可以迅速更新表单数据,让人感觉应用程序是立即完成的,表单没有提交或刷新而用户得到了新数据。 JavaScript 代码甚至可以对收到的数据执行某种计算,再发送另一个请求,完全不需要用户干预!这就是 XMLHttpRequest
的强大之处。它可以根据需要自行与服务器进行交互,用户甚至可以完全不知道幕后发生的一切。结果就是类似于桌面应用程序的动态、快速响应、高交互性的体验,但是背后又拥有互联网的全部强大力量。
得到 XMLHttpRequest
的句柄后,其他的 JavaScript 代码就非常简单了。事实上,我们将使用 JavaScript 代码完成非常基本的任务:
- 获取表单数据:JavaScript 代码很容易从 HTML 表单中抽取数据并发送到服务器。
- 修改表单上的数据:更新表单也很简单,从设置字段值到迅速替换图像。
- 解析 HTML 和 XML:使用 JavaScript 代码操纵 DOM,处理 HTML 表单服务器返回的 XML 数据的结构。
getElementById()
方法5 创建xmlhttprequest对象,兼容不同的浏览器
/* Create a new XMLHttpRequest object to talk to the Web server */
var xmlHttp = false;
/*@cc_on @*/
/*@if (@_jscript_version >= 5)
try {
xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e2) {
xmlHttp = false;
}
}
@end @*/
if (!xmlHttp && typeof XMLHttpRequest != 'undefined') {
xmlHttp = new XMLHttpRequest();
}
XMLHttpReaquest对象的属性:
属 性 | 描 述 |
onreadystatechange | 指定当readyState属性改变时的事件处理句柄,属性为只写 |
readyState | 返回当前请求的状态,属性为只读 |
responseBody | 将回应信息正文以unsigned byte数组形式返回,属性为只读 |
responseStream | 以Ado Stream对象的形式返回响应信息,属性为只读 |
responseText | 以字符串的形式返回服务器响应信息,属性为只读 |
responseXML | 将响应信息格式化为XML Document对象返回,属性为只读 |
status | 返回当前HTTP请求的状态码,属性为只读。如:404 = "文件未找到" 、200 = "成功" |
statusText | 返回当前HTTP请求的状态行,属性为只读 |
XMLHttpRequest对象属性readyState返回当前XMLHttp请求的状态,这些状态用长度为4的整形数据表示,其属性的状态含义如表
状 态 | 含 义 | 说 明 |
0 | 未初始化 | 对象已经建立,但是未初始化,即尚未调用open方法创建http请求 |
1 | 初始化 | 对象已经建立,但是为调用send方法发送http请求 |
2 | 发送数据 | send方法已经被调用,但是当前的状态以及http头未知 |
3 | 数据传送中 | 已经接收部分数据,因为响应及http头不全,这是通过response系列方法获取部分数据会出现错误 |
4 | 传送完成 | 数据接收完毕,此时可以通过response系列方法获取完整的回应数据 |
XMLHttpRequest对象属性onreadystatechange是readyState状态改变的事件触发器,用来指定当readyState属性发生改变时的处理事件。在使用过程中,通常通过将事件处理函数名称赋予onreadystatechange的方式,来为XMLHttpRequest指定事件触发器,而在事件处理函数中判断readyState状态值并做相应的处理。例程4-26的代码段指定doState- ReadyHandler函数作为事件处理函数,并在doStateReadyHandler函数体内在readyState状态为4时弹出一个显示“完成”信息的对话框。
例程4-26 指定XMLHttpRequest对象的回调函数
var http_request = null;
http_request = new ActiveXObject("Msxml2.XMLHTTP");
function send() {
http_request.onreadystatechange = doStateReadyHandler;
http_request.open("GET","http://localhost/sample.xml",true);
http_request.send();
}
function doStateReadyHandler() {
if(http_request.readySatate==4) window.alert("完成");
}
XMLHttpRequest对象属性responseText将响应信息以字符串的形式返回。XMLHttp- Request尝试将响应信息解码为Unicode字符串,默认的响应数据编码方式为UTF-8。如果服务器返回的数据带有BOM(byte-order mark),则XMLHttpRequest可以解码任何的UCS-2或者UCS-4数据。如果服务器返回的是XML文档,此属性不处理XML文档中的编码声明,仅将整个XML文档作为字符串返回。
如果服务器以XML文档的格式返回响应数据,这时应该采用responseXML属性加以处理。如果响应数据不是有效的XML文档,此属性本身不返回XMLDOMParseError,可以通过处理过的DOMDocument对象获取错误信息。在使用responseXML将服务器响应数据以XML文档的形式返回之前,先要将响应的内容类型设置为application/xml。
XMLHttpRequest对象属性status代表当前http请求的状态,为长整型数据。其值及其含义如表4-19所示。
表4-19 http请求状态及其含义
值 | 描 述 | 值 | 描 述 |
100 | 客户必须继续发出请求 | 404 | 没有发现文件、查询或URl |
101 | 客户要求服务器根据请求转换HTTP协议版本 | 405 | 用户在Request-Line字段定义的方法不允许 |
200 | 交易成功 | 406 | 根据用户发送的Accept拖,请求资源不可访问 |
201 | 提示知道新文件的URL | 407 | 类似401,用户必须首先在代理服务器上得到授权 |
202 | 接受和处理、但处理未完成 | 408 | 客户端没有在用户指定的饿时间内完成请求 |
203 | 返回信息不确定或不完整 | 409 | 对当前资源状态,请求不能完成 |
204 | 请求收到,但返回信息为空 | 410 | 服务器上不再有此资源且无进一步的参考地址 |
205 | 服务器完成了请求,用户代理必须复位当前已经浏览过的文件 | 411 | 服务器拒绝用户定义的Content-Length属性请求 |
206 | 服务器已经完成了部分用户的GET请求 | 412 | 一个或多个请求头字段在当前请求中错误 |
300 | 请求的资源可在多处得到 | 413 | 请求的资源大于服务器允许的大小 |
301 | 删除请求数据 | 414 | 请求的资源URL长于服务器允许的长度 |
302 | 在其他地址发现了请求数据 | 415 | 请求资源不支持请求项目格式 |
303 | 建议客户访问其他URL或访问方式 | 416 | 请求中包含Range请求头字段,在当前请求资源范围内没有range指示值,请求也不包含If-Range请求头字段 |
304 | 客户端已经执行了GET,但文件未变化 | 417 | 服务器不满足请求Expect头字段指定的期望值,如果是代理服务器,可能是下一级服务器不能满足请求 |
305 | 请求的资源必须从服务器指定的地址得到 | 500 | 服务器产生内部错误 |
307 | 申明请求的资源临时性删除 | 501 | 服务器不支持请求的函数 |
400 | 错误请求,如语法错误 | 502 | 服务器暂时不可用,有时是为了防止发生系统过载 |
401 | 请求授权失败 | 503 | 服务器过载或暂停维修 |
402 | 保留有效ChargeTo头响应 | 504 | 关口过载,服务器使用另一个关口或服务来响应用户,等待时间设定值较长 |
403 | 请求不允许 | 505 | 服务器不支持或拒绝支请求头中指定的HTTP版本 |
在这些状态中,最常用到的是“404”。通常,在类似例子4-20中doStateReady Handler的事件处理函数中,判断status的状态,然后做相应的处理。
XMLHttpRequest对象提供了包括send、open在内的六种方法,用来向服务器发送http请求,并设置相应的头信息。
XMLHttpRequest对象的方法
方 法 | 描 述 |
abort | 取消当前请求 |
getAllResourceHeaders | 获取相应的全部http头信息 |
getResourceHeader | 从响应信息中获取指定的http头信息 |
open | 创建一个新的http请求,并指定此请求的方法、URL、以及验证信息(用户名/密码) |
send | 发送请求到http服务器并接收回应 |
setRequestHeader | 单独设定请求的某个http头 |
语法第三部分:AJAX中的高级请求
headers =http_request.getAllResourceHeaders();
header = http_request.getResourceHeader(“header-name”);
6 ajax世界里的请求/响应
function callServer() {
// Get the city and state from the web form
var city = document.getElementById("city").value;
var state = document.getElementById("state").value;
// Only go on if there are values for both fields
if ((city == null) || (city == "")) return;
if ((state == null) || (state == "")) return;
// Build the URL to connect to
var url = "/scripts/getZipCode.php?city=" + escape(city) + "&state=" + escape(state);
// Open a connection to the server
xmlHttp.open("GET", url, true);
// Setup a function for the server to run when it's done
xmlHttp.onreadystatechange = updatePage;
// Send the request
xmlHttp.send(null);
}
7处理响应
function updatePage() {
if (xmlHttp.readyState == 4) {
var response = xmlHttp.responseText;
document.getElementById("zipCode").value = response;
}
}zipCode
是一个普通的文本字段,它可以保持例子简单,说明有时候可能希望 用户能够修改服务器返回的数据。
要记住这两点,它们对于好的用户界面设计来说很重要。
8 链接WEB表单
<form>
<p>City: <input type="text" name="city" id="city" size="25"
onChange="callServer();" /></p>
<p>State: <input type="text" name="state" id="state" size="25"
onChange="callServer();" /></p>
<p>Zip Code: <input type="text" name="zipCode" id="city" size="5" /></p>
</form>
本文将在上一篇文章的基础上重点介绍这个请求对象的 3 个关键部分的内容:
*HTTP 就绪状态
*HTTP 状态代码
*可以生成的请求类型
1 就绪状态
- 0:请求未初始化(还没有调用
open()
)。 - 1:请求已经建立,但是还没有发送(还没有调用
send()
)。 - 2:请求已发送,正在处理中(通常现在可以从响应中获取内容头)。
- 3:请求在处理中;通常响应中已有部分数据可用了,但是服务器还没有完成响应的生成。
- 4:响应已完成;您可以获取并使用服务器的响应了。
XMLHttpRequest
对象在多个函数之间生成多个请求。在这种(不常见的)情况中,您可能会在生成新请求之前希望确保请求对象是处于未初始化状态(readyState == 0
)。这实际上是要确保另外一个函数没有同时使用这个对象。2 如果您碰到请求方面的问题,这就是用来发现问题的首要之处。最好的方式是在 Internet Explorer 和 Firefox 都进行一下测试 —— 您会看到所有这 4 种状态,并可以检查请求的每个状态所处的情况。
3 HTTP 状态代码
- 401:未经授权
- 403:禁止
- 404:没找到
- 405: 表示不允许使用诸如发送 HEAD 请求之类不可接受的请求方法
- 407 :表示需要进行代理认证
- 200:一切良好
- 301:永久移动
- 302:找到(请求被重新定向到另外一个 URL/URI 上)
- 305:使用代理(请求必须使用一个代理来访问所请求的资源)
清单 8. 检查有效状态代码
function updatePage() {5 如果在有错误的信息的时候想给用户更好的体验,就要给出更高级的错误报告,这就需要更好的理解
if (request.readyState == 4) {
if (request.status == 200) {
var response = request.responseText.split("|");
document.getElementById("order").value = response[0];
document.getElementById("address").innerHTML =
response[1].replace(//n/g, "<br />");
} else if (request.status == 404) {
alert ("Requested URL is not found.");
} else if (request.status == 403) {
alert("Access denied.");
} else
alert("status is " + request.status);
}
}
xmlhttprequest
- 如果您可以考虑各种就绪状态 —— 并且理解了这些就绪状态在不同浏览器之间的区别 —— 就可以快速调试应用程序了。您甚至可以基于就绪状态而开发一些创造性的功能,并向用户和客户回报请求的状态。
- 如果您要对状态代码进行控制,就可以设置应用程序来处理脚本错误、非预期的响应以及边缘情况。结果是应用程序在所有的时间都可以正常工作,而不仅仅是只能一切都正常的情况下才能运行。
- 增加这种生成 HEAD 请求的能力,检查某个 URL 是否存在,以及确认某个文件是否被修改过,这样就可以确保用户可以获得有效的页面,用户所看到的信息都是最新的,(最重要的是)让他们惊讶这个应用程序是如何健壮和通用。
第四部分:利用DOM进行WEB相应
<html>
<head>
<title>Trees, trees, everywhere</title>
</head>
<body>
<h1>Trees, trees, everywhere</h1>
<p>Welcome to a <em>really</em> boring page.</p>
<div>
Come again soon.
<img src="come-again.gif" />
</div>
</body>
</html>
head
和 body
元素是 html
根元素的孩子;title
是 head
的孩子,而文本 “Trees, trees, everywhere” 是 title
的孩子,h1,p,div是body的孩子,Trees, trees, everywhere是h1的孩子,p,welcome to a,em,boring page是p的孩子,really是em的孩子,come again soon,img是div的孩子,这里面有文本有元素
getAttribute('id') 这是按名称获取属性的值,还可以是document.getelementbyid('id值'),value
第五部分 操纵DOM
最重要的节点类型是:
元素类型 | 节点类型 |
---|---|
元素 | 1 |
属性 | 2 |
文本 | 3 |
注释 | 8 |
文档 | 9 |
1 如果向 DOM 树中增加一个元素,这个元素就会立即出现在用户的 Web 浏览器中 —— 不需要重新加载页面 这里的意思是局部刷新而不需要全部刷新,不需要重新编写文本文件!
2 DOM 树中的每个元素和每段文本都有一个父亲,这个父节点可能是另一个元素(比如嵌套在 p
元素中的 img
)的孩子,或者 DOM 树中的顶层元素(这是每个文档中都出现一次的特殊情况,即使用 html
元素的地方),兄弟节点(与元素或文本 “相邻的” 节点)也就是同级的节点
3 DOM 代码中最常用的任务就是在页面的 DOM 树中导航。比方说,可以通过其 “id” 属性定位一个 form
,然后开始处理那个 form
中内嵌的元素和文本。其中可能包含文字说明、输入字段的标签、真正的 input
元素,以及其他 HTML 元素(如 img
)和链接(a
元素)
4 DOM 节点的属性主要有:
nodeName
报告节点的名称(详见下述)。nodeValue
提供节点的 “值”(详见后述)。parentNode
返回节点的父节点。记住,每个元素、属性和文本都有一个父节点。childNodes
是节点的孩子节点列表。对于 HTML,该列表仅对元素有意义,文本节点和属性节点都没有孩子。firstChild
仅仅是childNodes
列表中第一个节点的快捷方式。lastChild
是另一种快捷方式,表示childNodes
列表中的最后一个节点。previousSibling
返回当前节点之前 的节点。换句话说,它返回当前节点的父节点的childNodes
列表中位于该节点前面的那个节点(如果感到迷惑,重新读前面一句)。nextSibling
类似于previousSibling
属性,返回父节点的childNodes
列表中的下一个节点。attributes
仅用于元素节点,返回元素的属性列表。
6 清单 1. 使用 DOM 中的节点属性
// These first two lines get the DOM tree for the current Web page, |
7 节点方法
insertBefore(newChild, referenceNode)
将newChild
节点插入到referenceNode
之前。记住,应该对newChild
的目标父节点调用该方法。replaceChild(newChild, oldChild)
用newChild
节点替换oldChild
节点。removeChild(oldChild)
从运行该方法的节点中删除oldChild
节点。appendChild(newChild)
将newChild
添加到运行该函数的节点之中。newChild
被添加到目标节点孩子列表中的末端。hasChildNodes()
在调用该方法的节点有孩子时则返回 true,否则返回 false。hasAttributes()
在调用该方法的节点有属性时则返回 true,否则返回 false。
<html> |
8 没有
getNodeName()
方法,而要直接使用 nodeName
属性。因此节点对象(以及其他 DOM 对象)通过属性而不是函数公开了大量数据,就是属性.nodeValue得到数据。9 很多情况下文本节点的
nodeName
被报告为 “#text”,直接访问 myNode.nodeName
然后使用该值是危险的,很多情况下这个值为空。10 通用节点类型
- 文档节点表示整个 HTML 文档。
- 元素节点表示 HTML 元素,如
a
或img
。 - 属性节点表示 HTML 元素的属性,如
href
(a
元素)或src
(img
元素)。 - 文本节点表示 HTML 文档中的文本,如 “Click on the link below for a complete set list”。这是出现在
p
、a
或h2
这些元素中的文字。
也可使用 document
对象创建新节点,如下所示:
createElement(elementName)
使用给定的名称创建一个元素。createTextNode(text)
使用提供的文本创建一个新的文本节点。createAttribute(attributeName)
用提供的名称创建一个新属性。
这里的关键在于这些方法创建节点,但是并没有将其附加或者插入到特定的文档中。因此,必须使用前面所述的方法如 insertBefore()
或 appendChild()
来完成这一步。因此,可使用下面的代码创建新元素并将其添加到文档中:
var pElement = myDocument.createElement("p"); |
12 元素节点
- 与属性处理有关的方法:
getAttribute(name)
返回名为name
的属性值。removeAttribute(name)
删除名为name
的属性。setAttribute(name, value)
创建一个名为name
的属性并将其值设为value
。getAttributeNode(name)
返回名为name
的属性节点(属性节点在 下一节 介绍)。removeAttributeNode(node)
删除与指定节点匹配的属性节点。
- 与查找嵌套元素有关的方法:
getElementsByTagName(elementName)
返回具有指定名称的元素节点列表。这个与get
这些方法意义都很清楚,但还是来看几个例子吧。
处理元素很简单,比如可用 document
对象和上述方法创建一个新的 img
元素:
var imgElement = document.createElement("img"); |
查找嵌套元素
发现嵌套的元素很容易。比如,下面的代码用于发现和删除 清单 3 所示 HTML 页面中的所有 img
元素:
// Remove all the top-level <img> elements in the body |
也可以使用 getElementsByTagName()
完成类似的功能:
|
13
DOM 将属性表示成节点,可以通过元素的 attributes
来访问元素的属性,如下所示:
|
虽然也能使用属性节点,但通常使用元素类的方法处理属性更简单。其中包括:
getAttribute(name)
返回名为name
的属性值。removeAttribute(name)
删除名为name
的属性。setAttribute(name, value)
创建一个名为name
的属性并将其值设为value
。
这三个方法不需要直接处理属性节点。但允许使用简单的字符串属性设置和删除属性及其值。
14 文本节点需要考虑的最后一种节点是文本节点(至少在处理 HTML DOM 树的时候如此)。基本上通常用于处理文本节点的所有属性都属于节点对象。实际上,一般使用 nodeValue
属性来访问文本节点的文本,如下所示:
var pElements = bodyElement.getElementsByTagName("p"); |
少数其他几种方法是专门用于文本节点的。这些方法用于增加或分解节点中的数据:
appendData(text)
将提供的文本追加到文本节点的已有内容之后。insertData(position, text)
允许在文本节点的中间插入数据。在指定的位置插入提供的文本。replaceData(position, length, text)
从指定位置开始删除指定长度的字符,用提供的文本代替删除的文本。
1 建立一个简单的包含一些特殊效果的 Web 页面,所有这些都使用 JavaScript 操纵 DOM 来创建,不 需要重新加载或者刷新页面。
2 新建一个标签并增加属性和值
var newImage = document.createElement("img"); |
3 现在有了要插入的图片,还需要找到插入的地方。但是不能将其插入到已有的图片中,而是要将其插入到已有图片之前然后再删除原来的图片。为此需要知道已有图片的父元素,实际上这就是插入和删除操作的真正关键所在
4 应该记得,前面的文章中曾经指出 DOM 确实把网页看成一棵树,即节点的层次结构。每个节点都有父节点(树中更高层次的节点,该节点是它的一个子级),可能还有自己的子节点。对于图片来说,它没有子级 —— 要记住图片是空元素,但是它肯定有父节点。
5 插入新图片删除就图片
var imgParent = hatImage.parentNode; |
6 插入的简单做法
imgParent = hatImage.parentNode;
imgParent.replaceChild(newImage, hatImage);
7 插入的更简单用法
要记住,图片元素很大程度上是由其
src
属性控制的,他引用了某个地方的文件(不论是本地 URI 还是外部 URL)。到目前为止,我们一直用新图片替换图片节点,但是直接修改已有图片的 src
属性要简单得多!这样就避免了创建新节点、寻找父节点和替换旧节点的所有工作,只要一步就能完成了:
hatImage.setAttribute("src", "rabbit-hat.gif"); |
省略了 insertBefore();和 removeChild();
8 js控制按钮
var button = document.getElementById("hocusPocus");在这里面执行函数是不需要接括号的
button.setAttribute("value", "Hocus Pocus!");
button.onclick = showRabbit;
掌握第7部分:在请求和响应中使用XML(1)
1
XMLHttpRequest
对象更多的是关于在不重新加载页面的情况发出请求,而不会太多地涉及 XML 甚至 HTTP。2 虽然 XML 可以通过 HTTP 发送,但 XML 是一种数据格式而不是传输协议
3 和普通文本相比,XML 通常总会占用更多的空间,速度也更慢,因为需要在消息中增加 XML 所需要 的标签和语义。
4 如果从普通文本开始,然后发现确实需要 XML,那么就使用它;但是如果从一开始就使用 XML,基本 上可以肯定一定会降低应用程序的响应性。
5 要清楚什么时候使用 XML,不要一开始就认为它在很多情况下都能够加快应用程序;但,它可以增强 灵活性,这就是我们现在要讨论的。
6 使用普通文本发送名/值对
function callServer() {将名/值对转化成 XML
// Get the city and state from the Web form
var firstName = document.getElementById("firstName").value;
var lastName = document.getElementById("lastName").value;
var street = document.getElementById("street").value;
var city = document.getElementById("city").value;
var state = document.getElementById("state").value;
var zipCode = document.getElementById("zipCode").value;
// Build the URL to connect to
var url = "/scripts/saveAddress.php?firstName=" + escape(firstName) +
"&lastName=" + escape(lastName) + "&street=" + escape(street) +
"&city=" + escape(city) + "&state=" + escape(state) +
"&zipCode=" + escape(zipCode);
// Open a connection to the server
xmlHttp.open("GET", url, true);
// Set up a function for the server to run when it's done
xmlHttp.onreadystatechange = confirmUpdate;
// Send the request
xmlHttp.send(null);
}
当然,XML 要求有一个根元素;如果使用文档片段(XML 文档的一部分)的话则需要一个封闭元素。因此可能需要将上述 XML 转化成下面的形式:
<address>注意两点不同:
<firstName>Larry</firstName>
<lastName>Gullahorn</lastName>
<street>9018 Heatherhorn Drive</street>
<city>Rowlett</city>
<state>Texas</state>
<zipCode>75080</zipCode>
</address>
清单 2. 用 XML 发送名/值对
function callServer() {
// Get the city and state from the Web form
var firstName = document.getElementById("firstName").value;
var lastName = document.getElementById("lastName").value;
var street = document.getElementById("street").value;
var city = document.getElementById("city").value;
var state = document.getElementById("state").value;
var zipCode = document.getElementById("zipCode").value;
var xmlString = "<profile>" +
" <firstName>" + escape(firstName) + "</firstName>" +
" <lastName>" + escape(lastName) + "</lastName>" +
" <street>" + escape(street) + "</street>" +
" <city>" + escape(city) + "</city>" +
" <state>" + escape(state) + "</state>" +
" <zip-code>" + escape(zipCode) + "</zip-code>" +
"</profile>";
// Build the URL to connect to
var url = "/scripts/saveAddress.php";
// Open a connection to the server
xmlHttp.open("POST", url, true);
// Tell the server you're sending it XML
xmlHttp.setRequestHeader("Content-Type", "text/xml");
// Set up a function for the server to run when it's done
xmlHttp.onreadystatechange = confirmUpdate;
// Send the request
xmlHttp.send(xmlString);
}
建立 XML 之后,按照和发送文本基本相同的方式打开连接。对于 XML 最好使用 POST 请求,
因为有些浏览器限制了 GET 请求字符串的长度,而 XML 可能很长,可以看到清单 2 中把
GET 改成了 POST 方法。此外,XML 通过send()
方法发送,而不是附加在请求 URL 最后的参数。
- 来自客户机的 XML 封装在
address
元素,但是服务器要求数据封装在profile
元素中。 - 来自客户机的 XML 使用了
zipCode
元素,而服务器希望邮政编码放在zip-code
元素中。
7 使用XML传输必须编写一行新的代码:
xmlHttp.setRequestHeader("Content-Type", "text/xml");1 使用XML好的用法:服务器向客户机返回 XML 响应。使服务器发送 XML 来响应请求是一个好 主意
8 使用xml传输增加的读取标签的时间,因此除非和只接受 XML 的脚本(确实存在这样的脚本)打交道,
在请求中最好使用普通文本
第8部分:在请求和响应中使用XML(2)
2 在绝大多数 HTTP 请求中,转义序列
%20
用于表示一个空格,文本 “Live Together, Die Alone” 将以
Live%20Together,%20Die%20Alone
的形式通过 HTTP 发送。escape(Live Together,Die Alone)=
Live%20Together,%20Die%20Alone
3 客户机不需要使用 XML,因为他们会使用名称/值对发送请求但是服务器无法以GET方式发送名值对以响应客户
机
4 但如果服务器要一次性发回电视剧 Lost, Alias 和 Six Degrees 的近期收视率又该怎么办呢?
尽管可以选择许多种方法来使用纯文本发送这一响应(清单 1 给出了一些示例),但没有一种是不
需客户机进行某些处理的极其简单的方法
清单 1. 收视率的服务器响应(不同版本)
show=Alias&ratings=6.5|show=Lost&ratings=14.2|show=Six%20Degrees&ratings=9.1 |
尽管不难找到拆分这些响应字符串的方法,但客户机将不得不根据分号、等号、竖线和与符号解析并拆分这些字符串。这不是编写使其他开发人员能够轻松理解和维护的健壮代码的方法。所以使用xml代替纯文本方式会使客户端接收到的数据更有可读性,比如下面的格式传递上面的内容一般的程序员都会易于理解
<ratings>
<show>
<title>Alias</title>
<rating>6.5</rating>
</show>
<show>
<title>Lost</title>
<rating>14.2</rating>
</show>
<show>
<title>Six Degrees</title>
<rating>9.1</rating>
</show>
</ratings>
5 本文章对于服务器端程序如何才能生成 XML 响应的技术细节没有深入的讨论
6 将 XML 作为纯文本处理 在这种情况下,您要使用请求对象的responseText
属性,就像在服务器向您发
送非 XML 响应时一样
清单 4. 将 XML 作为普通服务器响应处理
function updatePage() {
if (request.readyState == 4) {
if (request.status == 200) {
var response = request.responseText;
// response has the XML response from the server
alert(response);
}
}
}
response 变量的值
<ratings><show><title>Alias</title><rating>6.5</rating> |
用这样的方法获得XML数据是不好拆分的,最好是使用下面的范式处理XML
7 将 XML 当成 XML 回调函数使用的是responseXML
属性。该属性在XMLHttpRequest
上可用,它以 DOM 文
档的格式返回服务器的响应
清单 6. 将 XML 当作 XML
function updatePage() {
if (request.readyState == 4) {
if (request.status == 200) {
var xmlDoc = request.responseXML;
// work with xmlDoc using the DOM
}
}
}
现在您有了一个 DOMDocument
,可以像处理其他任何 XML 一样处理它。
遍历所有 show 元素
function updatePage() { |
通过这段非常简单的代码,您正是将 XML 响应作为 XML 而不是无格式的纯文本进行了处理,还使用了一点 DOM 和简单的
JavaScript 来处理服务器响应。更重要的是,您使用了标准化的格式 ——
XML,而不是以逗号分隔的值或以竖线分隔的名称/值对。换句话说,您将 XML
用在了最适合它的地方,避免了在不适合的地方使用它(比如说向服务器发送请求时)。
8 服务器端的 XML:一个简单的示例
返回 XML 的 PHP 脚本
<?php |
第九部分:使用google ajax search api
9 如果您处于这样一个环境中:服务器向您发送的数据非常有限,或者采用的是奇怪的逗号分隔、竖线分隔
的格式,那么 XML 可能会给您带来真正的收益。考虑处理或更改您的服务器端组件,以使它们用更为标准
化的方式 —— 使用 XML —— 来返回响应,而不是使用那些健壮性比 XML 差的专用格式。
1 可以与一些公共 API,例如来自 Google 或 Amazon 的 API 进行通信,从而为 Web 应用程序增加您自己的脚本 和服务器端程序所不能提供的更多功能
2 在线文章和教程
如果在 IBM developerWorks 上发表文章,而又不提及 Internet 上的文章、教程、白皮书之类的大量参考资 料,这无疑很愚蠢。网上有成百上千份教材,您也许可以发现近千篇关于 Ajax 的文章 -- 在本系列中,我就已经发表了近十篇文章!这些文章大部分都有可用的代码、例子、下载以及其他各种类型的资源。
如果您没有能力编写要使用的服务器端程序或脚本,或者找不到所需的开放源码程序或脚本,那么可以打开 Google 网站,试着输入对要找内容的基本描述。然后再在 developerWorks 网站上执行相同的操作。您常常可以发现所需的代码,甚至是整个脚本,并且还有一些有帮助的注释和关于其工作方式的描述。
3 如果不是因为技术上的原因,而是因为数据而受到限制,那么,一个公共 API 也许可以帮助您解决问题。公共 API 允许使用其他人的服务器上的程序并使用其他人的数据。
4 开放的google API http://code.google.com/apis/ajaxsearch/
5 这个就是如何在自己的网站上面添加google的搜索引擎
6 Ajax 应用程序不仅仅是指使用 XmlHttpRequest;可以说是一种基于异步方式开发 Web 应用程序的方法。即使 您没有编写任何特定于 Ajax 的代码,也仍然创建了一个 Ajax 应用程序。
第十部分:使用JSON进行数据传输
1选择的意义
解决任何问题的选择越多,找到问题的最佳 解决方案的可能性就越大,这比只能使用一个 解决方案要好得多
在实际的应用中使用名称/值对传递数据是最好的选择,XML 通常更适合用来向 Ajax 应用程序做出响应,而不是从Ajax 应用程序发出请求。
2 json是将数据对象转换成字符串,然后在函数当中传递,js可以很容易解释JSON
3 JSON表示多个值的例子
{ "programmers": [4
{ "firstName": "Brett", "lastName":"McLaughlin", "email": "brett@newInstance.com" },
{ "firstName": "Jason", "lastName":"Hunter", "email": "jason@servlets.com" },
{ "firstName": "Elliotte", "lastName":"Harold", "email": "elharo@macfaq.com" }
],
"authors": [
{ "firstName": "Isaac", "lastName": "Asimov", "genre": "science fiction" },
{ "firstName": "Tad", "lastName": "Williams", "genre": "fantasy" },
{ "firstName": "Frank", "lastName": "Peretti", "genre": "christian fiction" }
],
"musicians": [
{ "firstName": "Eric", "lastName": "Clapton", "instrument": "guitar" },
{ "firstName": "Sergei", "lastName": "Rachmaninoff", "instrument": "piano" }
]
使用这种形式要比XML节省空间
}
在 JavaScript 中使用 JSON,JavaScript 中处理 JSON 数据不需要任何特殊的 API 或工具包。
例如,可以创建一个新的 JavaScript 变量,然后将 JSON 格式的数据字符串直接赋值给它:
var people = |
这非常简单;现在 people
包含前面看到的 JSON 格式的数据。但是,这还不够,因为访问数据的方式似乎还不明显。
访问数据只需在 JavaScript 中使用下面这样的代码:
people.programmers[0].lastName; |
结果是字符串值 “McLaughlin”。
people.musicians[1].lastName = "Rachmaninov"; |
转换回字符串
当然,如果不能轻松地将对象转换回本文提到的文本格式,那么所有数据修改都没有太大的价值。在 JavaScript 中这种转换也很简单:
String newJSONtext = people.toJSONString(); |
这样就行了!现在就获得了一个可以在任何地方使用的文本字符串,例如,可以将它用作 Ajax 应用程序中的请求字符串。
更重要的是,可以将任何 JavaScript 对象转换为 JSON 文本。并非只能处理原来用 JSON 字符串赋值的变量。为了对名为 myObject
的对象进行转换,只需执行相同形式的命令:
String myObjectInJSON = myObject.toJSONString(); |
这就是 JSON 与本系列讨论的其他数据格式之间最大的差异。如果使用 JSON,只需调用一个简单的函数,就可以获得经过格式化的数据,可以直接使用了。对于其他数据格式,需要在原始数据和格式化数据之间进行转换。即使使用 Document Object Model 这样的 API(提供了将自己的数据结构转换为文本的函数),也需要学习这个 API 并使用 API 的对象,而不是使用原生的 JavaScript 对象和语法。
最终结论是,如果要处理大量 JavaScript 对象,那么 JSON 几乎肯定是一个好选择,这样就可以轻松地将数据转换为可以在请求中发送给服务器端程序的格式。
结束语
本 系列已经用大量时间讨论了数据格式,这主要是因为几乎所有异步应用程序最终都要处理数据。如果掌握了发送和接收所有类型的数据的各种工具和技术,并按照最 适合每种数据类型的方式使用它们,那么就能够更精通 Ajax。在掌握 XML 和纯文本的基础上,再掌握 JSON,这样就能够在 JavaScript 中处理更复杂的数据结构。
第十一部分:在服务器端的JSON
1 本部分将讨论发送数据以外的问题,深入介绍服 务器端程序如何接收和处理 JSON 格式的数据。还要讨论服务器端程序如何跨脚本和服务器端组件以 JSON 格式发送回数据,这样就可以将 XML、纯文本和 JSON 请求和响应混合在一起。这可以提供很大的灵活性,可以按照几乎任何组合结合使用所有这些工具。
2解决post带来的时时更新的问题var url = "organizePeople.php?timeStamp=" + new Date().getTime();
另一个简单提示是 URL 的末尾追加了时间。这就确保了请求不会在它第一次被发送后即缓存,而是会在此方法每次被调用后重新创建和重发;此 URL 会由于时间戳的不同而稍微有些不同。这种技巧常被用于确保到脚本的 POST 每次都会实际生成新请求且 Web 服务器不会尝试缓存来自服务器的响应。
3
JSON 是适用于 Ajax 应用程序的一种有效格式,原因是它使 JavaScript 对象和字符串值之间得以快速转换。由于 Ajax 应用程序非常适合将纯文本发送给服务器端程序并对应地接收纯文本,相比不能生成文本的 API,能生成文本的 API 自然更可取;而且,JSON 让您能够处理本地 JavaScript 对象,而无需为如何表示这些对象多费心思。
XML 也可以提供文本方面的类似益处,但用于将 JavaScript 对象转换成 XML 的几个现有 API 没有 JSON API 成熟;有时,您必须在创建和处理 JavaScript 对象时格外谨慎以确保所进行的处理能与所选用的 XML 会话 API 协作。但对于 JSON,情况就大不相同:它能处理几乎所有可能的对象类型,并会返回给您一个非常好的 JSON 数据表示。因此,JSON 的最大价值在于可以将 JavaScript 真的作为 JavaScript 而非数据格式语言进行处理。您所学到的所有有关使用 JavaScript 对象的技巧都可以应用到代码中,而无需为如何将这些对象转变成文本而多费心思。这之后,可以进行如下所示的简单 JSON 方法调用:
String myObjectInJSON = myObject.toJSONString(); |
现在就可以将结果文本发送给服务器了。
通过 GET 以名称/值对发送 JSON
将 JSON 数据发给服务器的最简单方法是将其转换成文本,然后以名称/值对的值的方式进行发送。
|
如果要以名称/值对将其发送到服务器端,应该如下所示:
var url = "organizePeople.php?people=" + people.toJSONString(); |
这看起来不错,但却存在一个问题:在 JSON 数据中会有空格和各种字符,Web 浏览器往往要尝试对其继续编译。要确保这些字符不会在服务器上(或者在将数据发送给服务器的过程中)引起混乱,需要在 JavaScript escape()
函数中做如下添加:
var url = "organizePeople.php?people=" + escape( |
该函数可以处理空格、斜线和其他任何可能影响浏览器的内容,并将它们转换成 Web 可用字符(比如,空格会被转换成 %20
,浏览器并不会将其视为空格处理,而是不做更改,将其直接传递到服务器)。之后,服务器会(通常自动)再把它们转换回它们传输后的本来 “面目”。
这种做法的缺点有两个:
- 在使用 GET 请求发送大块数据时,对 URL 字符串有长度限制。虽然这个限制很宽泛,但对象的 JSON 字符串表示的长度可能超出您的想象,尤其是在使用极其复杂的对象时更是如此。
- 在跨网络以纯文本发送所有数据的时候,发送数据面临的不安全性超出了您的处理能力。
简言之,以上是 GET 请求的两个限制,而不是简单的两个与 JSON 数据相关的事情。在想要发送用户名和姓之外的更多内容,比如表单中的选择时,二者可能会需要多加注意。若要处理任何机密或极长的内容,可以使用 POST 请求。
当决定使用 POST 请求将 JSON 数据发送给服务器时,并不需要对代码进行大量更改,如下所示:
var url = "organizePeople.php?timeStamp=" + new Date().getTime(); |
第 3 部分重点介绍了如何发送 POST 请求。请求使用 POST 而非 GET 打开,而且 Content-Type 头被设置为让服务器预知它能得到何种数据。在这种情况下,即为 application/x-www-form-urlencoded
,它让服务器知道现在发送的是文本,正如它从常规的 HTML 表单中得到的一样。
另 一个简单提示是 URL 的末尾追加了时间。这就确保了请求不会在它第一次被发送后即缓存,而是会在此方法每次被调用后重新创建和重发;此 URL 会由于时间戳的不同而稍微有些不同。这种技巧常被用于确保到脚本的 POST 每次都会实际生成新请求且 Web 服务器不会尝试缓存来自服务器的响应。
不管使用 GET 还是 POST,关键之处在于 JSON 就只是文本。由于不需要特殊编码而且每个服务器端脚本都能处理文本数据,所以可以轻松利用 JSON 并将其应用到服务器。假如 JSON 是二进制格式的或是一些怪异的文本编码,情况就不这么简单了;幸好 JSON 只是常规的文本数据(正如脚本能从表单提交中所接收到的数据,在 POST 段和 Content-Type 头中亦可以看出),所以在将数据发送到服务器时无需太费心。
在此时,您在客户端所做的选择(比如使用 JavaScript 对象,然后将其转换成 JSON 字符串)必须要与服务器端的选择相匹配,比如使用哪个 API 解码 JSON 数据。
不管在服务器端使用何种语言,在服务器端处理 JSON 基本上就需要两个步骤。
- 针对编写服务器端程序所用的语言,找到相应的 JSON 解析器/工具箱/帮助器 API。
- 使用 JSON 解析器/工具箱/帮助器 API 取得来自客户机的请求数据并将数据转变成脚本能理解的东西。
寻找 JSON 解析器或工具箱最好的资源是 JSON 站点。 在这里,除了可以了解此格式本身的方方面面之外,还可以通过各种链接找到 JSON 的各种工具和解析器,您只需针对自己编写脚本所用的语言下载相应的工具箱即可。为了让服务器端脚本和程序能够使用此工具箱,可以根据情况对其进行选择、扩 展或安装(如果在服务器端使用的是 C#、PHP 或 Lisp,则可变性更大)。
例如,如果使用的是 PHP,可以简单将其升级至 PHP 5.2 并用它完成操作;在 PHP 这个最新版本默认包含了 JSON 扩展。实际上,那也是在使用 PHP 时处理 JSON 的最好方法。
一旦获得了程序可用的资源,剩下的事就是找到合适的方法进行调用。比如,假设为 PHP 使用的是 JSON-PHP 模板:
// This is just a code fragment from a larger PHP server-side script |
通过该模板,可将获得的所有数据(数组格式的、多行的、单值的或 JSON 数据结构中的任何内容)转换成原生 PHP 格式,放在 $value
变量中。
至此,您应该从技术角度对如何在服务器端处理 JSON 有了基本的把握。JSON 是一种多么灵活、强大的数据格式。即使您不会在每个应用程序中都使用 JSON,但优秀的 Ajax 和 JavaScript 程序员的工具箱中总少不了 JSON 以备不时之需。
http://www.ibm.com/developerworks/cn/web/wa-ajaxintro/