本系列的上一期文章(请参阅 参考资料 中的连接),咱们介绍了 Ajax 应用程序,考察了推进 Ajax 应用程序的基本概念。其中的核心是不少您可能已经了解的技术:JavaScript、HTML 和 XHTML、一点动态 HTML 以及 DOM(文档对象模型)。本文将放大其中的一点,把目光放到具体的 Ajax 细节上。ajax
本文中,您将开始接触最基本和基础性的有关 Ajax 的所有对象和编程方法:XMLHttpRequest
对象。该对象实际上仅仅是一个跨越全部 Ajax 应用程序的公共线程,您可能已经预料到,只有完全理解该对象才能充分发挥编程的潜力。事实上,有时您会发现,要正确地使用 XMLHttpRequest
,显然不能 使用XMLHttpRequest
。这究竟是怎么回事呢?正则表达式
Web 2.0 一瞥
在深刻研究代码以前首先看看最近的观点 —— 必定要十分清楚 Web 2.0 这个概念。听到 Web 2.0 这个词的时候,应该首先问一问 “Web 1.0 是什么?” 虽然不多听人提到 Web 1.0,实际上它指的就是具备彻底不一样的请求和响应模型的传统 Web。好比,到 Amazon.com 网站上点击一个按钮或者输入搜索项。就会对服务器发送一个请求,而后响应再返回到浏览器。该请求不只仅是图书和书目列表,而是另外一个完整的 HTML 页面。所以当 Web 浏览器用新的 HTML 页面重绘时,可能会看到闪烁或抖动。事实上,经过看到的每一个新页面能够清晰地看到请求和响应。编程
Web 2.0(在很大程度上)消除了这种看得见的往复交互。好比访问 Google Maps 或 Flickr 这样的站点(到这些支持 Web 2.0 和 Ajax 站点的连接请参阅 参考资料)。好比在 Google Maps 上,您能够拖动地图,放大和缩小,只有不多的重绘操做。固然这里仍然有请求和响应,只不过都藏到了幕后。做为用户,体验更加温馨,感受很像桌面应用程序。这种新的感觉和范型就是当有人提到 Web 2.0 时您所体会到的。
须要关心的是如何使这些新的交互成为可能。显然,仍然须要发出请求和接收响应,但正是针对每次请求/响应交互的 HTML 重绘形成了缓慢、笨拙的 Web 交互的感觉。所以很清楚,咱们须要一种方法使发送的请求和接收的响应只 包含须要的数据而不是整个 HTML 页面。唯一须要得到整个新 HTML 页面的时候就是但愿用户看到 新页面的时候。
但多数交互都是在已有页面上增长细节、修改主体文本或者覆盖原有数据。这些状况下,Ajax 和 Web 2.0 方法容许在不 更新整个 HTML 页面的状况下发送和接收数据。对于那些常常上网的人,这种能力可让您的应用程序感受更快、响应更及时,让他们不时地光顾您的网站。
XMLHttpRequest 简介
要真正实现这种绚丽的奇迹,必须很是熟悉一个 JavaScript 对象,即 XMLHttpRequest
。这个小小的对象实际上已经在几种浏览器中存在一段时间了,它是本专栏从此几个月中要介绍的 Web 2.0、Ajax 和大部分其余内容的核心。为了让您快速地大致了解它,下面给出将要用于该对象的不多的几个 方法和属性。
open()
:创建到服务器的新请求。send()
:向服务器发送请求。abort()
:退出当前请求。readyState
:提供当前 HTML 的就绪状态。responseText
:服务器返回的请求响应文本。
若是不了解这些(或者其中的任何 一个),您也不用担忧,后面几篇文章中咱们将介绍每一个方法和属性。如今应该 了解的是,明确用XMLHttpRequest
作什么。要注意这些方法和属性都与发送请求及处理响应有关。事实上,若是看到 XMLHttpRequest
的全部方法和属性,就会发现它们都 与很是简单的请求/响应模型有关。显然,咱们不会遇到特别新的 GUI 对象或者建立用户交互的某种超极神秘的方法,咱们将使用很是简单的请求和很是简单的响应。听起来彷佛没有多少吸引力,可是用好该对象能够完全改变您的应用程序。
简单的 new
首先须要建立一个新变量并赋给它一个 XMLHttpRequest
对象实例。这在 JavaScript 中很简单,只要对该对象名使用 new
关键字便可,如 清单 1 所示。
清单 1. 建立新的 XMLHttpRequest 对象
<script language="javascript" type="text/javascript"> var request = new XMLHttpRequest(); </script>
不难吧?记住,JavaScript 不要求指定变量类型,所以不须要像 清单 2 那样作(在 Java 语言中可能须要这样)。
清单 2. 建立 XMLHttpRequest 的 Java 伪代码
XMLHttpRequest request = new XMLHttpRequest();
所以在 JavaScript 中用 var
建立一个变量,给它一个名字(如 “request”),而后赋给它一个新的 XMLHttpRequest
实例。此后就能够在函数中使用该对象了。
错误处理
在实际上各类事情均可能出错,而上面的代码没有提供任何错误处理。较好的办法是建立该对象,并在出现问题时优雅地退出。好比,任何较早的浏览器(不论您是否相信,仍然有人在使用老版本的 Netscape Navigator)都不支持 XMLHttpRequest
,您须要让这些用户知道有些地方出了问题。清单 3 说明如何建立该对象,以便在出现问题的时候发出 JavaScript 警告。
清单 3. 建立具备错误处理能力的 XMLHttpRequest
<script language="javascript" type="text/javascript"> var request = false; try { request = new XMLHttpRequest(); } catch (failed) { request = false; } if (!request) alert("Error initializing XMLHttpRequest!"); </script>
必定要理解这些步骤:
- 建立一个新变量
request
并赋值 false。后面将使用 false 做为断定条件,它表示尚未建立XMLHttpRequest
对象。 - 增长 try/catch 块:
- 尝试建立
XMLHttpRequest
对象。 - 若是失败(
catch (failed)
)则保证request
的值仍然为 false。
- 尝试建立
- 检查
request
是否仍为 false(若是一切正常就不会是 false)。 - 若是出现问题(
request
是 false)则使用 JavaScript 警告通知用户出现了问题。
代码很是简单,对大多数 JavaScript 和 Web 开发人员来讲,真正理解它要比读写代码花更长的时间。如今已经获得了一段带有错误检查的XMLHttpRequest
对象建立代码,还能够告诉您哪儿出了问题。
应付 Microsoft
看起来彷佛一切良好,至少在用 Internet Explorer 试验这些代码以前是这样的。若是这样试验的话,就会看到 图 1 所示的糟糕情形。
图 1. Internet Explorer 报告错误

显然有什么地方不对劲,而 Internet Explorer 很难说是一种过期的浏览器,由于全世界有 70% 在使用 Internet Explorer。换句话说,若是不支持 Microsoft 和 Internet Explorer 就不会受到 Web 世界的欢迎!所以咱们须要采用不一样的方法处理 Microsoft 浏览器。
经验证发现 Microsoft 支持 Ajax,可是其 XMLHttpRequest
版本有不一样的称呼。事实上,它将其称为几种 不一样的东西。若是使用较新版本的 Internet Explorer,则须要使用对象 Msxml2.XMLHTTP
,而较老版本的 Internet Explorer 则使用 Microsoft.XMLHTTP
。咱们须要支持这两种对象类型(同时还要支持非 Microsoft 浏览器)。请看看 清单 4,它在前述代码的基础上增长了对 Microsoft 的支持。
清单 4. 增长对 Microsoft 浏览器的支持
<script language="javascript" type="text/javascript"> var request = false; try { request = new XMLHttpRequest(); } catch (trymicrosoft) { try { request = new ActiveXObject("Msxml2.XMLHTTP"); } catch (othermicrosoft) { try { request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (failed) { request = false; } } } if (!request) alert("Error initializing XMLHttpRequest!"); </script>
很容易被这些花括号迷住了眼睛,所以下面分别介绍每一步:
- 建立一个新变量
request
并赋值 false。使用 false 做为判断条件,它表示尚未建立XMLHttpRequest
对象。 - 增长 try/catch 块:
- 尝试建立
XMLHttpRequest
对象。 - 若是失败(
catch (trymicrosoft)
):- 尝试使用较新版本的 Microsoft 浏览器建立 Microsoft 兼容的对象(
Msxml2.XMLHTTP
)。 - 若是失败(
catch (othermicrosoft)
)尝试使用较老版本的 Microsoft 浏览器建立 Microsoft 兼容的对象(Microsoft.XMLHTTP
)。
- 尝试使用较新版本的 Microsoft 浏览器建立 Microsoft 兼容的对象(
- 若是失败(
catch (failed)
)则保证request
的值仍然为 false。
- 尝试建立
- 检查
request
是否仍然为 false(若是一切顺利就不会是 false)。 - 若是出现问题(
request
是 false)则使用 JavaScript 警告通知用户出现了问题。
这样修改代码以后再使用 Internet Explorer 试验,就应该看到已经建立的表单(没有错误消息)。我实验的结果如 图 2 所示。
图 2. Internet Explorer 正常工做

静态与动态
再看一看清单 1、3 和 4,注意,全部这些代码都直接嵌套在 script
标记中。像这种不放到方法或函数体中的 JavaScript 代码称为静态 JavaScript。就是说代码是在页面显示给用户以前的某个时候运行。(虽然根据规范不能彻底精确地 知道这些代码什么时候运行对浏览器有什么影响,可是能够保证这些代码在用户可以与页面交互以前运行。)这也是多数 Ajax 程序员建立 XMLHttpRequest
对象的通常方式。
就是说,也能够像 清单 5 那样将这些代码放在一个方法中。
清单 5. 将 XMLHttpRequest 建立代码移动到方法中
<script language="javascript" type="text/javascript"> var request; function createRequest() { try { request = new XMLHttpRequest(); } catch (trymicrosoft) { try { request = new ActiveXObject("Msxml2.XMLHTTP"); } catch (othermicrosoft) { try { request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (failed) { request = false; } } } if (!request) alert("Error initializing XMLHttpRequest!"); } </script>
若是按照这种方式编写代码,那么在处理 Ajax 以前须要调用该方法。所以还须要 清单 6 这样的代码。
清单 6. 使用 XMLHttpRequest 的建立方法
<script language="javascript" type="text/javascript"> var request; function createRequest() { try { request = new XMLHttpRequest(); } catch (trymicrosoft) { try { request = new ActiveXObject("Msxml2.XMLHTTP"); } catch (othermicrosoft) { try { request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (failed) { request = false; } } } if (!request) alert("Error initializing XMLHttpRequest!"); } function getCustomerInfo() { createRequest(); // Do something with the request variable } </script>
此代码唯一的问题是推迟了错误通知,这也是多数 Ajax 程序员不采用这一方法的缘由。假设一个复杂的表单有 10 或 15 个字段、选择框等,当用户在第 14 个字段(按照表单顺序从上到下)输入文本时要激活某些 Ajax 代码。这时候运行 getCustomerInfo()
尝试建立一个XMLHttpRequest
对象,但(对于本例来讲)失败了。而后向用户显示一条警告,明确地告诉他们不能使用该应用程序。但用户已经花费了不少时间在表单中输入数据!这是很是使人讨厌的,而讨厌显然不会吸引用户再次访问您的网站。
若是使用静态 JavaScript,用户在点击页面的时候很快就会看到错误信息。这样也很烦人,是否是?可能令用户错误地认为您的 Web 应用程序不能在他的浏览器上运行。不过,固然要比他们花费了 10 分钟输入信息以后再显示一样的错误要好。所以,我建议编写静态的代码,让用户尽量早地发现问题。
用 XMLHttpRequest 发送请求
获得请求对象以后就能够进入请求/响应循环了。记住,XMLHttpRequest
唯一的目的是让您发送请求和接收响应。其余一切都是 JavaScript、CSS 或页面中其余代码的工做:改变用户界面、切换图像、解释服务器返回的数据。准备好 XMLHttpRequest
以后,就能够向服务器发送请求了。
欢迎使用沙箱
Ajax 采用一种沙箱安全模型。所以,Ajax 代码(具体来讲就是 XMLHttpRequest
对象)只能对所在的同一个域发送请求。之后的文章中将进一步介绍安全和 Ajax,如今只要知道在本地机器上运行的代码只能对本地机器上的服务器端脚本发送请求。若是让 Ajax 代码在 www.breakneckpizza.com 上运行,则必须 www.breakneck.com 中运行的脚本发送请求。
设置服务器 URL
首先要肯定链接的服务器的 URL。这并非 Ajax 的特殊要求,但仍然是创建链接所必需的,显然如今您应该知道如何构造 URL 了。多数应用程序中都会结合一些静态数据和用户处理的表单中的数据来构造该 URL。好比,清单 7 中的 JavaScript 代码获取电话号码字段的值并用其构造 URL。
清单 7. 创建请求 URL
<script language="javascript" type="text/javascript"> var request = false; try { request = new XMLHttpRequest(); } catch (trymicrosoft) { try { request = new ActiveXObject("Msxml2.XMLHTTP"); } catch (othermicrosoft) { try { request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (failed) { request = false; } } } if (!request) alert("Error initializing XMLHttpRequest!"); function getCustomerInfo() { var phone = document.getElementById("phone").value; var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone); } </script>
这里没有难懂的地方。首先,代码建立了一个新变量 phone
,并把 ID 为 “phone” 的表单字段的值赋给它。清单 8 展现了这个表单的 XHTML,其中能够看到 phone
字段及其 id
属性。
清单 8. Break Neck Pizza 表单
<body> <p><img src="breakneck-logo_4c.gif" alt="Break Neck Pizza" /></p> <form action="POST"> <p>Enter your phone number: <input type="text" size="14" name="phone" id="phone" onChange="getCustomerInfo();" /> </p> <p>Your order will be delivered to:</p> <div id="address"></div> <p>Type your order in here:</p> <p><textarea name="order" rows="6" cols="50" id="order"></textarea></p> <p><input type="submit" value="Order Pizza" id="submit" /></p> </form> </body>
还要注意,当用户输入电话号码或者改变电话号码时,将触发 清单 8 所示的 getCustomerInfo()
方法。该方法取得电话号码并构造存储在url
变量中的 URL 字符串。记住,因为 Ajax 代码是沙箱型的,于是只能链接到同一个域,实际上 URL 中不须要域名。该例中的脚本名为/cgi-local/lookupCustomer.php
。最后,电话号码做为 GET 参数附加到该脚本中:"phone=" + escape(phone)
。
若是之前没用见过 escape()
方法,它用于转义不能用明文正确发送的任何字符。好比,电话号码中的空格将被转换成字符 %20
,从而可以在 URL 中传递这些字符。
能够根据须要添加任意多个参数。好比,若是须要增长另外一个参数,只须要将其附加到 URL 中并用 “与”(&
)字符分开 [第一个参数用问号(?
)和脚本名分开]。
打开请求
有了要链接的 URL 后就能够配置请求了。能够用 XMLHttpRequest
对象的 open()
方法来完成。该方法有五个参数:
- request-type:发送请求的类型。典型的值是
GET
或POST
,但也能够发送HEAD
请求。 - url:要链接的 URL。
- asynch:若是但愿使用异步链接则为 true,不然为 false。该参数是可选的,默认为 true。
- username:若是须要身份验证,则能够在此指定用户名。该可选参数没有默认值。
- password:若是须要身份验证,则能够在此指定口令。该可选参数没有默认值。
一般使用其中的前三个参数。事实上,即便须要异步链接,也应该指定第三个参数为 “true”。这是默认值,但坚持明确指定请求是异步的仍是同步的更容易理解。
将这些结合起来,一般会获得 清单 9 所示的一行代码。
清单 9. 打开请求
function getCustomerInfo() { var phone = document.getElementById("phone").value; var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone); request.open("GET", url, true); }
一旦设置好了 URL,其余就简单了。多数请求使用 GET
就够了(后面的文章中将看到须要使用 POST
的状况),再加上 URL,这就是使用open()
方法须要的所有内容了。
挑战异步性
本系列的后面一篇文章中,我将用不少时间编写和使用异步代码,可是您应该明白为何 open()
的最后一个参数这么重要。在通常的请求/响应模型中,好比 Web 1.0,客户机(浏览器或者本地机器上运行的代码)向服务器发出请求。该请求是同步的,换句话说,客户机等待服务器的响应。当客户机等待的时候,至少会用某种形式通知您在等待:
- 沙漏(特别是 Windows 上)。
- 旋转的皮球(一般在 Mac 机器上)。
- 应用程序基本上冻结了,而后过一段时间光标变化了。
这正是 Web 应用程序让人感到笨拙或缓慢的缘由 —— 缺少真正的交互性。按下按钮时,应用程序实际上变得不能使用,直到刚刚触发的请求获得响应。若是请求须要大量服务器处理,那么等待的时间可能很长(至少在这个多处理器、DSL 没有等待的世界中是如此)。
而异步请求不 等待服务器响应。发送请求后应用程序继续运行。用户仍然能够在 Web 表单中输入数据,甚至离开表单。没有旋转的皮球或者沙漏,应用程序也没有明显的冻结。服务器悄悄地响应请求,完成后告诉原来的请求者工做已经结束(具体的办法很快就会看到)。结果是,应用程序感受不 那么迟钝或者缓慢,而是响应迅速、交互性强,感受快多了。这仅仅是 Web 2.0 的一部分,但它是很重要的一部分。全部老套的 GUI 组件和 Web 设计范型都不能克服缓慢、同步的请求/响应模型。
发送请求
一旦用 open()
配置好以后,就能够发送请求了。幸运的是,发送请求的方法的名称要比 open()
适当,它就是 send()
。
send()
只有一个参数,就是要发送的内容。可是在考虑这个方法以前,回想一下前面已经经过 URL 自己发送过数据了:
var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone);
虽然可使用 send()
发送数据,但也能经过 URL 自己发送数据。事实上,GET
请求(在典型的 Ajax 应用中大约占 80%)中,用 URL 发送数据要容易得多。若是须要发送安全信息或 XML,可能要考虑使用 send()
发送内容(本系列的后续文章中将讨论安全数据和 XML 消息)。若是不须要经过 send()
传递数据,则只要传递 null
做为该方法的参数便可。所以您会发如今本文中的例子中只须要这样发送请求(参见 清单 10)。
清单 10. 发送请求
function getCustomerInfo() { var phone = document.getElementById("phone").value; var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone); request.open("GET", url, true); request.send(null); }
指定回调方法
如今咱们所作的只有不多一点是新的、革命性的或异步的。必须认可,open()
方法中 “true” 这个小小的关键字创建了异步请求。可是除此以外,这些代码与用 Java servlet 及 JSP、PHP 或 Perl 编程没有什么两样。那么 Ajax 和 Web 2.0 最大的秘密是什么呢?秘密就在于XMLHttpRequest
的一个简单属性 onreadystatechange
。
首先必定要理解这些代码中的流程(若是须要请回顾 清单 10)。创建其请求而后发出请求。此外,由于是异步请求,因此 JavaScript 方法(例子中的 getCustomerInfo()
)不会等待服务器。所以代码将继续执行,就是说,将退出该方法而把控制返回给表单。用户能够继续输入信息,应用程序不会等待服务器。
这就提出了一个有趣的问题:服务器完成了请求以后会发生什么?答案是什么也不发生,至少对如今的代码而言如此!显然这样不行,所以服务器在完成经过 XMLHttpRequest
发送给它的请求处理以后须要某种指示说明怎么作。
如今 onreadystatechange
属性该登场了。该属性容许指定一个回调函数。回调容许服务器(猜获得吗?)反向调用 Web 页面中的代码。它也给了服务器必定程度的控制权,当服务器完成请求以后,会查看 XMLHttpRequest
对象,特别是 onreadystatechange
属性。而后调用该属性指定的任何方法。之因此称为回调是由于服务器向网页发起调用,不管网页自己在作什么。比方说,可能在用户坐在椅子上手没有碰键盘的时候调用该方法,可是也可能在用户输入、移动鼠标、滚动屏幕或者点击按钮时调用该方法。它并不关心用户在作什么。
这就是称之为异步的缘由:用户在一层上操做表单,而在另外一层上服务器响应请求并触发 onreadystatechange
属性指定的回调方法。所以须要像 清单 11 同样在代码中指定该方法。
清单 11. 设置回调方法
function getCustomerInfo() { var phone = document.getElementById("phone").value; var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone); request.open("GET", url, true); request.onreadystatechange = updatePage; request.send(null); }
须要特别注意的是该属性在代码中设置的位置 —— 它是在调用 send()
以前 设置的。发送请求以前必须设置该属性,这样服务器在回答完成请求以后才能查看该属性。如今剩下的就只有编写 updatePage()
方法了,这是本文最后一节要讨论的重点。
处理服务器响应
发送请求,用户高兴地使用 Web 表单(同时服务器在处理请求),而如今服务器完成了请求处理。服务器查看 onreadystatechange
属性肯定要调用的方法。除此之外,能够将您的应用程序看做其余应用程序同样,不管是否异步。换句话说,不必定要采起特殊的动做编写响应服务器的方法,只须要改变表单,让用户访问另外一个 URL 或者作响应服务器须要的任何事情。这一节咱们重点讨论对服务器的响应和一种典型的动做 —— 即时改变用户看到的表单中的一部分。
回调和 Ajax
如今咱们已经看到如何告诉服务器完成后应该作什么:将 XMLHttpRequest
对象的 onreadystatechange
属性设置为要运行的函数名。这样,当服务器处理完请求后就会自动调用该函数。也不须要担忧该函数的任何参数。咱们从一个简单的方法开始,如 清单 12 所示。
清单 12. 回调方法的代码
<script language="javascript" type="text/javascript"> var request = false; try { request = new XMLHttpRequest(); } catch (trymicrosoft) { try { request = new ActiveXObject("Msxml2.XMLHTTP"); } catch (othermicrosoft) { try { request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (failed) { request = false; } } } if (!request) alert("Error initializing XMLHttpRequest!"); function getCustomerInfo() { var phone = document.getElementById("phone").value; var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone); request.open("GET", url, true); request.onreadystatechange = updatePage; request.send(null); } function updatePage() { alert("Server is done!"); } </script>
它仅仅发出一些简单的警告,告诉您服务器何时完成了任务。在本身的网页中试验这些代码,而后在浏览器中打开(若是但愿查看该例中的 XHTML,请参阅 清单 8)。输入电话号码而后离开该字段,将看到一个弹出的警告窗口(如 图 3 所示),可是点击 OK 又出现了……
图 3. 弹出警告的 Ajax 代码

根据浏览器的不一样,在表单中止弹出警告以前会看到两次、三次甚至四次警告。这是怎么回事呢?原来咱们尚未考虑 HTTP 就绪状态,这是请求/响应循环中的一个重要部分。
HTTP 就绪状态
前面提到,服务器在完成请求以后会在 XMLHttpRequest
的 onreadystatechange
属性中查找要调用的方法。这是真的,但还不完整。事实上,每当 HTTP 就绪状态改变时它都会调用该方法。这意味着什么呢?首先必须理解 HTTP 就绪状态。
HTTP 就绪状态表示请求的状态或情形。它用于肯定该请求是否已经开始、是否获得了响应或者请求/响应模型是否已经完成。它还能够帮助肯定读取服务器提供的响应文本或数据是否安全。在 Ajax 应用程序中须要了解五种就绪状态:
- 0:请求没有发出(在调用
open()
以前)。 - 1:请求已经创建但尚未发出(调用
send()
以前)。 - 2:请求已经发出正在处理之中(这里一般能够从响应获得内容头部)。
- 3:请求已经处理,响应中一般有部分数据可用,可是服务器尚未完成响应。
- 4:响应已完成,能够访问服务器响应并使用它。
与大多数跨浏览器问题同样,这些就绪状态的使用也不尽一致。您也许指望任务就绪状态从 0 到 一、二、3 再到 4,但实际上不多是这种状况。一些浏览器从不报告 0 或 1 而直接从 2 开始,而后是 3 和 4。其余浏览器则报告全部的状态。还有一些则屡次报告就绪状态 1。在上一节中看到,服务器屡次调用 updatePage()
,每次调用都会弹出警告框 —— 可能和预期的不一样!
对于 Ajax 编程,须要直接处理的唯一状态就是就绪状态 4,它表示服务器响应已经完成,能够安全地使用响应数据了。基于此,回调方法中的第一行应该如 清单 13 所示。
清单 13. 检查就绪状态
function updatePage() { if (request.readyState == 4) alert("Server is done!"); }
修改后就能够保证服务器的处理已经完成。尝试运行新版本的 Ajax 代码,如今就会看到与预期的同样,只显示一次警告信息了。
HTTP 状态码
虽然 清单 13 中的代码看起来彷佛不错,可是还有一个问题 —— 若是服务器响应请求并完成了处理可是报告了一个错误怎么办?要知道,服务器端代码应该明白它是由 Ajax、JSP、普通 HTML 表单或其余类型的代码调用的,但只能使用传统的 Web 专用方法报告信息。而在 Web 世界中,HTTP 代码能够处理请求中可能发生的各类问题。
比方说,您确定遇到过输入了错误的 URL 请求而获得 404 错误码的情形,它表示该页面不存在。这仅仅是 HTTP 请求可以收到的众多错误码中的一种(完整的状态码列表请参阅 参考资料 中的连接)。表示所访问数据受到保护或者禁止访问的 403 和 401 也很常见。不管哪一种状况,这些错误码都是从完成的响应 获得的。换句话说,服务器履行了请求(即 HTTP 就绪状态是 4)可是没有返回客户机预期的数据。
所以除了就绪状态外,还须要检查 HTTP 状态。咱们指望的状态码是 200,它表示一切顺利。若是就绪状态是 4 并且状态码是 200,就能够处理服务器的数据了,并且这些数据应该就是要求的数据(而不是错误或者其余有问题的信息)。所以还要在回调方法中增长状态检查,如 清单 14 所示。
清单 14. 检查 HTTP 状态码
function updatePage() { if (request.readyState == 4) if (request.status == 200) alert("Server is done!"); }
为了增长更健壮的错误处理并尽可能避免过于复杂,能够增长一两个状态码检查,请看一看 清单 15 中修改后的 updatePage()
版本。
清单 15. 增长一点错误检查
function updatePage() { if (request.readyState == 4) if (request.status == 200) alert("Server is done!"); else if (request.status == 404) alert("Request URL does not exist"); else alert("Error: status code is " + request.status); }
如今将 getCustomerInfo()
中的 URL 改成不存在的 URL 看看会发生什么。应该会看到警告信息说明要求的 URL 不存在 —— 好极了!很难处理全部的错误条件,可是这一小小的改变可以涵盖典型 Web 应用程序中 80% 的问题。
读取响应文本
如今能够确保请求已经处理完成(经过就绪状态),服务器给出了正常的响应(经过状态码),最后咱们能够处理服务器返回的数据了。返回的数据保存在 XMLHttpRequest
对象的 responseText
属性中。
关于 responseText
中的文本内容,好比格式和长度,有意保持含糊。这样服务器就能够将文本设置成任何内容。比方说,一种脚本可能返回逗号分隔的值,另外一种则使用管道符(即 |
字符)分隔的值,还有一种则返回长文本字符串。何去何从由服务器决定。
在本文使用的例子中,服务器返回客户的上一个订单和客户地址,中间用管道符分开。而后使用订单和地址设置表单中的元素值,清单 16 给出了更新显示内容的代码。
清单 16. 处理服务器响应
function updatePage() { 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, "
"); } else alert("status is " + request.status); } }
首先,获得 responseText
并使用 JavaScript split()
方法从管道符分开。获得的数组放到 response
中。数组中的第一个值 —— 上一个订单 —— 用 response[0]
访问,被设置为 ID 为 “order” 的字段的值。第二个值 response[1]
,即客户地址,则须要更多一点处理。由于地址中的行用通常的行分隔符(“\n”字符)分隔,代码中须要用 XHTML 风格的行分隔符 <br />
来代替。替换过程使用 replace()
函数和正则表达式完成。最后,修改后的文本做为 HTML 表单 div
中的内部 HTML。结果就是表单忽然用客户信息更新了,如图 4 所示。
图 4. 收到客户数据后的 Break Neck 表单

结束本文以前,我还要介绍 XMLHttpRequest
的另外一个重要属性 responseXML
。若是服务器选择使用 XML 响应则该属性包含(也许您已经猜到)XML 响应。处理 XML 响应和处理普通文本有很大不一样,涉及到解析、文档对象模型(DOM)和其余一些问题。后面的文章中将进一步介绍 XML。可是由于 responseXML
一般和 responseText
一块儿讨论,这里有必要提一提。对于不少简单的 Ajax 应用程序 responseText
就够了,可是您很快就会看到经过 Ajax 应用程序也能很好地处理 XML。
结束语
您可能对 XMLHttpRequest
感到有点厌倦了,我不多看到一整篇文章讨论一个对象,特别是这种简单的对象。可是您将在使用 Ajax 编写的每一个页面和应用程序中反复使用该对象。坦白地说,关于 XMLHttpRequest
还真有一些可说的内容。下一期文章中将介绍如何在请求中使用 POST
及GET
,来设置请求中的内容头部和从服务器响应读取内容头部,理解如何在请求/响应模型中编码请求和处理 XML。
再日后咱们将介绍常见 Ajax 工具箱。这些工具箱实际上隐藏了本文所述的不少细节,使得 Ajax 编程更容易。您也许会想,既然有这么多工具箱为什么还要对底层的细节编码。答案是,若是不知道应用程序在作什么,就很难发现应用程序中的问题。
所以不要忽略这些细节或者简单地浏览一下,若是便捷华丽的工具箱出现了错误,您就没必要挠头或者发送邮件请求支持了。若是了解如何直接使用 XMLHttpRequest
,就会发现很容易调试和解决最奇怪的问题。只有让其解决您的问题,工具箱才是好东西。
所以请熟悉 XMLHttpRequest
吧。事实上,若是您有使用工具箱的 Ajax 代码,能够尝试使用 XMLHttpRequest
对象及其属性和方法从新改写。这是一种不错的练习,能够帮助您更好地理解其中的原理。
下一期文章中将进一步讨论该对象,探讨它的一些更有趣的属性(如 responseXML
),以及如何使用 POST
请求和以不一样的格式发送数据。请开始编写代码吧,一个月后咱们再继续讨论。
参考资料
学习
- 您能够参阅本文在 developerWorks 全球站点上的 英文原文。
- 掌握 Ajax,第 1 部分: Ajax 简介(developerWorks,2005 年 12 月)帮助您了解 Ajax,这是一种构建网站的高生产率方法。(本文中的参考资料列表都值得访问!)
- 面向 Java 开发人员的 Ajax: 构建动态的 Java 应用程序(developerWorks,2005 年 9 月)从 Java 的角度考察了 Ajax 服务器端。
- 面向 Java 开发人员的 Ajax: Ajax 的 Java 对象序列化(developerWorks,2005 年 10 月)从 Java 的角度分析了如何经过网络发送对象以及与 Ajax 交互。
- 使用 AJAX 调用 SOAP Web 服务,第 1 部分: 构建 Web 服务客户机(developerWorks,2005 年 10 月)是关于集成 Ajax 和现有基于 SOAP 的 web 服务的至关高级的文章。
- Google GMail 是一个很好的例子,说明了基于 Ajax 的应用程序如何改变 Web 的工做方式。
- Google Maps 是另外一种基于 Google 的 Web 2.0 应用程序。
- Flickr 是一个很好的例子,说明如何使用 Ajax 建立相似桌面的 Web 应用程序。
- Ajax: A New Approach to Web Applications 发明了 Ajax 一词,全部 Ajax 开发人员都应该读一读。
- Why Ajax Matters Now 告诉您为何 Ajax 很重要。
- 若是使用的是 Microsoft 浏览器 Internet Explorer,请访问 Microsoft Developer Network's XML Developer Center。
- 请经过 在线文档 进一步了解 MSXML,Microsoft XML 解析器。
- 看一看响应中包含的全部 HTTP 状态码 列表。
- developerWorks Web Architecture 专区 专门发表各类基于 Web 的解决方案的文章。
得到产品和技术
- Elisabeth Freeman、Eric Freeman 和 Brett McLaughlin 合著的 Head Rush Ajax(2005 年 2 月,O'Reilly Media, Inc.)以 Head First 风格将本文中所述的内容灌输到您的头脑中。
- Java and XML, Second Edition(Brett McLaughlin,2001 年 8 月,O'Reilly Media, Inc.)包括做者关于 XHTML 和 XML 转换的讨论。
- JavaScript: The Definitive Guide(David Flanagan,2001 年 11 月,O'Reilly Media, Inc.)详细介绍了如何使用 JavaScript、动态网页,第二版增长了关于 Ajax 的两章。
- Head First HTML with CSS & XHTML(Elizabeth 和Eric Freeman,2005 年 12 月,O'Reilly Media, Inc.)是学习 XHTML、CSS 以及如何将二者结合起来的完整参考。
讨论
- 参与论坛讨论。
- developerWorks blogs:加入 developerWorks 社区。