XMLHttpRequest
要真正实现绚丽的奇迹web2.0桌面式的B/S程序,必须非常熟悉一个 JavaScript 对象,即 XMLHttpRequest。这个小小的对象实际上已经在几种浏览器中存在一段时间了,它Web 2.0、Ajax 和大部分其他内容的核心。为了让您快速地大体了解它,下面给出将要用于该对象的几个方法和属性。
·open():建立到服务器的新请求。
·send():向服务器发送请求。
·abort():退出当前请求。
·readyState:提供当前 HTML 的就绪状态。
·responseText:服务器返回的请求响应文本。
静态与动态
不放到方法或函数体中的 JavaScript 代码称为静态 JavaScript。就是说代码是在页面显示给用户之前的某个时候运行。(虽然根据规范不能完全精确地 知道这些代码何时运行对浏览器有什么影响,但是可以保证这些代码在用户能够与页面交互之前运行)这也是多数 Ajax 程序员创建 XMLHttpRequest 对象的一般方式。那么放在方法体内的js代码就是动态代码了。不过根据用户体验友好程度和经验,一般创建XMLHttpRequest 对象都使用静态js代码。
用 XMLHttpRequest 发送请求
得到请求对象之后就可以进入请求/响应循环了。记住,XMLHttpRequest 惟一的目的是让您发送请求和接收响应。其他一切都是 JavaScript、CSS 或页面中其他代码的工作:改变用户界面、切换图像、解释服务器返回的数据。准备好 XMLHttpRequest 之后,就可以向服务器发送请求了。
沙箱
Ajax 采用一种沙箱安全模型。Ajax 代码(具体来说就是 XMLHttpRequest 对象)只能对所在的同一个域发送请求。现在只要知道在本地机器上运行的代码只能对本地机器上的服务器端脚本发送请求。
设置服务器 URL
首先要确定连接的服务器的 URL。这并不是 Ajax 的特殊要求,但仍然是建立连接所必需的,多数应用程序中都会结合一些静态数据和用户处理的表单中的数据来构造该 URL。传递参数的时候用escape() 方法包裹参数,以前没用见过escape() 方法,它用于转义不能用明文正确发送的任何字符。比如,电话号码中的空格将被转换成字符 %20,从而能够在 URL 中传递这些字符。+可以根据需要添加任意多个参数。比如,如果需要增加另一个参数,只需要将其附加到 URL 中并用 “与”(&)字符分开 [第一个参数用问号(?)和脚本名分开]。
打开请求
有了要连接的 URL 后就可以配置请求了。可以用 XMLHttpRequest 对象的 open() 方法来完成。 该方法有五个参数:
request-type:发送请求的类型。典型的值是 GET 或 POST,但也可以发送 HEAD 请求。
url:要连接的 URL。
asynch:如果希望使用异步连接则为 true,否则为 false。该参数是可选的,默认为 true。
username:如果需要身份验证,则可以在此指定用户名。该可选参数没有默认值。 password:如果需要身份验证,则可以在此指定口令。该可选参数没有默认值。 通常使用其中的前三个参数。事实上,即使需要异步连接,也应该指定第三个参数为 “true”。这是默认值,但坚持明确指定请求是异步的还是同步的更容易理解。
实际上open()方法并不是打开一个请求。如果监控 XHTML/Ajax 页面及其连接脚本之间的网络和数据传递,当调用 open() 方法时将看不到任何通信。不清楚为何选用了这个名字。
异步性
异步请求不等待服务器响应。发送请求后应用程序继续运行。用户仍然可以在 Web 表单中输入数据,甚至离开表单。没有旋转的皮球或者沙漏,应用程序也没有明显的冻结。服务器悄悄地响应请求,完成后告诉原来的请求者工作已经结束(具体的办法很快就会看到)。结果是,应用程序感觉不 那么迟钝或者缓慢,而是响应迅速、交互性强,感觉快多了。这仅仅是 Web 2.0 的一部分,但它是很重要的一部分。所有老套的 GUI 组件和 Web 设计范型都不能克服缓慢、同步的请求/响应模型。
发送请求
send() 只有一个参数,就是要发送的内容。虽然可以使用 send() 发送数据,但也能通过 URL 本身发送数据。事实上,GET 请求(在典型的 Ajax 应用中大约占 80%)中,用 URL 发送数据要容易得多。如果需要发送安全信息或 XML,可能要考虑使用 send() 发送内容。如果不需要通过 send() 传递数据,则只要传递 null 作为该方法的参数即可。因此您会发现在本文中的例子中只需要这样发送请求。
指定回调方法
秘密就在于 XMLHttpRequest 的一个简单属性 onreadystatechange。需要特别注意的是该属性在代码中设置的位置 —— 它是在调用 send() 之前 设置的。发送请求之前必须设置该属性,这样服务器在回答完成请求之后才能查看该属性。
JavaScript 中引用函数
JavaScript 是一种弱类型的语言,可以用变量引用任何东西。因此如果声明了一个函数 updatePage(),JavaScript 也将该函数名看作是一个变量。换句话说,可用变量名 updatePage 在代码中引用函数。
处理服务器响应
服务器完成了请求处理。服务器查看 onreadystatechange 属性确定要调用的方法。将 XMLHttpRequest 对象的 onreadystatechange 属性设置为要运行的函数名。这样,当服务器处理完请求后就会自动调用该函数。也不需要担心该函数的任何参数。 根据浏览器的不同,在表单停止弹出警告之前会看到两次、三次甚至四次警告。这是怎么回事呢?原来我们还没有考虑 HTTP 就绪状态,这是请求/响应循环中的一个重要部分。
HTTP 就绪状态
服务器在完成请求之后会在 XMLHttpRequest 的 onreadystatechange 属性中查找要调用的方法。事实上,每当 HTTP 就绪状态改变时它都会调用该方法。这意味着什么呢?首先必须理解 HTTP 就绪状态。
HTTP 就绪状态表示请求的状态或情形。它用于确定该请求是否已经开始、是否得到了响应或者请求/响应模型是否已经完成。它还可以帮助确定读取服务器提供的响应文本或数据是否安全。
在 Ajax 应用程序中需要了解五种就绪状态:
0:请求没有发出(在调用 open() 之前)。
1:请求已经建立但还没有发出(调用 send() 之前)。
2:请求已经发出正在处理之中(这里通常可以从响应得到内容头部)。
3:请求已经处理,响应中通常有部分数据可用,但是服务器还没有完成响应。
4:响应已完成,可以访问服务器响应并使用它。
与大多数跨浏览器问题一样,这些就绪状态的使用也不尽一致。您也许期望任务就绪状态从 0 到 1、2、3 再到 4,但实际上很少是这种情况。一些浏览器从不报告 0 或 1 而直接从 2 开始,然后是 3 和 4。其他浏览器则报告所有的状态。还有一些则多次报告就绪状态 1。
对于 Ajax 编程,需要直接处理的惟一状态就是就绪状态 4,它表示服务器响应已经完成,可以安全地使用响应数据了。
HTTP 状态码
还有一个问题 —— 如果服务器响应请求并完成了处理但是报告了一个错误怎么办?要知道,服务器端代码应该明白它是由 Ajax、JSP、普通 HTML 表单或其他类型的代码调用的,但只能使用传统的 Web 专用方法报告信息。而在 Web 世界中,HTTP 代码可以处理请求中可能发生的各种问题。
比方说,您肯定遇到过输入了错误的 URL 请求而得到 404 错误码的情形,它表示该页面不存在。这仅仅是 HTTP 请求能够收到的众多错误码中的一种。表示所访问数据受到保护或者禁止访问的 403 和 401 也很常见。无论哪种情况,这些错误码都是从完成的响应得到的。换句话说,服务器履行了请求(即 HTTP 就绪状态是 4)但是没有返回客户机预期的数据。
因此除了就绪状态外,还需要检查 HTTP 状态。我们期望的状态码是 200,它表示一切顺利。如果就绪状态是 4 而且状态码是 200,就可以处理服务器的数据了,而且这些数据应该就是要求的数据(而不是错误或者其他有问题的信息)。因此还要在回调方法中增加状态检查。
读取响应文本
确保请求已经处理完成(通过就绪状态),服务器给出了正常的响应(通过状态码),最后我们可以处理服务器返回的数据了。返回的数据保存在 XMLHttpRequest 对象的 responseText 属性中。
关于 responseText 中的文本内容,比如格式和长度,有意保持含糊。这样服务器就可以将文本设置成任何内容。比方说,一种脚本可能返回逗号分隔的值,另一种则使用管道符(即 | 字符)分隔的值,还有一种则返回长文本字符串。何去何从由服务器决定。
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 风格的行分隔符
来代替。替换过程使用 replace() 函数和正则表达式完成。最后,修改后的文本作为 HTML 表单 div 中的内部 HTML。结果就是表单突然用客户信息更新了。
XMLHttpRequest 的另一个重要属性 responseXML。如果服务器选择使用 XML 响应则该属性包含XML 响应。处理 XML 响应和处理普通文本有很大不同,涉及到解析、文档对象模型(DOM)和其他一些问题。
完整示例代码: