本文介绍了如何建立可以适应不一样浏览器的XMLHttpRequest实例,创建和发送请求,并响应服务器。您将开始接触最基本和基础性的有关Ajax的所有对象和编程方法:XMLHttpRequest对象。该对象实际上仅仅是一个跨越全部Ajax应用程序的公共线程,您可能已经预料到,只有完全理解该对象才能充分发挥编程的潜力。
XMLHttpRequest简介javascript
XMLHttpRequest 是JS的一个对象。它是介绍 Web 2.0、Ajax 和大部分其余内容的核心。下面给出该对象的几个方法和属性:
一、open():创建到服务器的新请求。
二、send():向服务器发送请求。
三、abort():退出当前请求。
四、readyState:提供当前 HTML 的就绪状态。
五、responseText:服务器返回的请求响应文本。
用XMLHttpRequest可以作什么呢,值得注意的是这些方法和属性都与发送请求及处理响应有关。事实上,若是看到XMLHttpRequest的全部方法和属性,就会发现它们都与很是简单的请求/响应模型有关。用好该对象能够完全改变您的应用程序。
建立XMLHttpRequest对象实例
首先须要建立一个新变量并赋给它一个XMLHttpRequest对象实例。这在JS中很简单,只要对该对象名使用new关键字便可.建立新的XMLHttpRequest对象:var request = new XMLHttpRequest();
建立 XMLHttpRequest的Java伪代码:XMLHttpRequest request = new XMLHttpRequest();
错误与跨浏览器处理
在实际上各类事情均可能出错,而上面的代码没有提供任何错误处理。较好的办法是建立该对象,并在出现问题时优雅地退出。好比,任何较早的浏览器都不支持 XMLHttpRequest,您须要让这些用户知道有些地方出了问题。下面说明如何建立该对象,以便在出现问题的时候发出 JavaScript 警告。
建立具备错误处理能力的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 警告通知用户出现了问题。
如今已经获得了一段带有错误检查的XMLHttpRequest对象建立代码,还能够告诉您哪儿出了问题。
增长对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对象。
四、检查 request 是否仍然为 false(若是一切顺利就不会是 false)。
五、若是出现问题(request 是 false)则使用 JavaScript 警告通知用户出现了问题。
这样修改代码以后再使用InternetExplorer试验,就应该看到已经建立的表单(没有错误消息)。
静态代码与动态代码
代码都直接嵌套在script标记中,不放到方法或函数体中的JS代码称为静态JS。这种状况代码是在页面显示给用户以前的某个时候运行。虽然根据规范不能彻底精确地知道这些代码什么时候运行对浏览器有什么影响,可是能够保证这些代码在用户可以与页面交互以前运行,这也是多数Ajax程序员建立XMLHttpRequest对象的通常方式。
将 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 以前须要调用该方法。所以还须要使用XMLHttpRequest的建立方法。
function getCustomerInfo() {
createRequest();
}
此方式唯一的问题是推迟了错误通知,这也是多数 Ajax 程序员不采用这一方法的缘由。若是使用静态JS,用户在点击页面的时候很快就会看到错误信息。这样也很烦人,是否是?可能令用户错误地认为您的Web应用程序不能在他的浏览器上运行。不过,固然要比他们花费了10 分钟输入信息以后再显示一样的错误要好。所以,我建议编写静态的代码,让用户尽量早地发现问题。
用XMLHttpRequest发送请求
获得请求对象以后就能够进入请求/响应循环了。记住XMLHttpRequest 唯一的目的是让您发送请求和接收响应。其余一切都是JS、CSS 或页面中其余代码的工做。如改变用户界面、切换图像、解释服务器返回的数据。准备好XMLHttpRequest 以后,就能够向服务器发送请求了。Ajax 采用一种沙箱安全模型。所以Ajax 代码(具体来讲就是XMLHttpRequest对象)只能对所在的同一个域发送请求。记住:在本地机器上运行的代码只能对本地机器上的服务器端脚本发送请求。如让Ajax代码在www.google.com上运行,则必须在www.google.com中运行的脚本发送请求。
设置服务器URL
首先要肯定链接的服务器的 URL。这并非Ajax的特殊要求,但仍然是创建链接所必需的,显然如今您应该知道如何构造URL了。多数应用程序中都会结合一些静态数据和用户处理的表单中的数据来构造该URL。
创建请求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” 的表单字段的值赋给它。下面展现了这个表单的HTML,其中能够看到phone字段及其id属性。
<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();" />php
span>
</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>
还要注意,当用户输入电话号码或者改变电话号码时,将触发getCustomerInfo() 方法。该方法取得电话号码并构造存储在url变量中的 URL字符串。记住,因为Ajax代码是沙箱型的,于是只能链接到同一个域,实际上URL中不须要域名。
escape() 方法是一个顶级JS方法,并不与任何对象关联。使用escape方法能够将属性值手工添加到URL中。escape方法编码指定字符串中的特定字符,并返回新字符串。它用于转义不能用明文正确发送的任何字符。好比电话号码中的空格将被转换成字符%20,从而可以在URL中传递这些字符。
能够根据须要添加任意多个参数。好比须要增长另外一个参数,只须要将其附加到URL中并用“与”(&)字符分开,第一个参数用问号(?)和脚本名分开。
打开请求
open() 是打开吗?Internet 开发人员对open() 方法到底作什么没有达成一致。但它实际上并非打开一个请求。若是监控 HTML/Ajax 页面及其链接脚本之间的网络和数据传递,当调用 open() 方法时将看不到任何通讯。不清楚为什么选用了这个名字,但显然不是一个好的选择。有了要链接的URL后就能够配置请求了。能够用XMLHttpRequest对象的open()方法来完成。该方法有五个参数:
一、request-type:发送请求的类型。典型的值是 GET 或 POST,但也能够发送 HEAD 请求。
二、url:要链接的 URL。
三、asynch:若是但愿使用异步链接则为 true,不然为 false。该参数是可选的,默认为 true。
四、username:若是须要身份验证,则能够在此指定用户名。该可选参数没有默认值。
五、password:若是须要身份验证,则能够在此指定口令。该可选参数没有默认值。
一般使用其中的前三个参数。事实上即便须要异步链接,也应该指定第三个参数为true。这是默认值,但坚持明确指定请求是异步的仍是同步的更容易理解。
function getCustomerInfo() {
var phone = document.getElementById("phone").value;
var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone);
request.open("GET", url, true);
}
一旦设置好了URL,其余就简单了。多数请求使用GET就够了,再加上URL,这就是使用open() 方法须要的所有内容了。
挑战异步性
编写和使用异步代码,您应该明白为何open() 的最后一个参数这么重要。在通常的请求/响应模型中,好比 Web 1.0,客户机(浏览器或者本地机器上运行的代码)向服务器发出请求。该请求是同步的,换句话说客户机等待服务器的响应。当客户机等待的时候,至少会用某种形式通知您在等待:
一、沙漏(特别是 Windows 上)。
二、旋转的皮球(一般在 Mac 机器上)。
三、应用程序基本上冻结了,而后过一段时间光标变化了。
这正是Web应用程序让人感到笨拙或缓慢的缘由——缺少真正的交互性。按下按钮时,应用程序实际上变得不能使用,直到刚刚触发的请求获得响应。若是请求须要大量服务器处理,那么等待的时间可能很长。而异步请求不等待服务器响应。发送请求后应用程序继续运行。用户仍然能够在Web表单中输入数据,甚至离开表单。没有旋转的皮球或者沙漏,应用程序也没有明显的冻结。服务器悄悄地响应请求,完成后告诉原来的请求者工做已经结束。结果是应用程序感受不那么迟钝或者缓慢,而是响应迅速、交互性强,感受快多了。这仅仅是Web 2.0的一部分,但它是很重要的一部分。全部Web2.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()发送内容。若是不须要经过send()传递数据,则只要传递null 做为该方法的参数便可。所以您会发如今本文中的例子中只须要这样发送请求。
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。
首先必定要理解这些代码中的流程。创建其请求而后发出请求。此外,由于是异步请求,因此JavaScript 方法(例子中的 getCustomerInfo())不会等待服务器。所以代码将继续执行,就是说,将退出该方法而把控制返回给表单。用户能够继续输入信息,应用程序不会等待服务器。这就提出了一个有趣的问题:服务器完成了请求以后会发生什么?答案是什么也不发生,至少对如今的代码而言如此!显然这样不行,所以服务器在完成经过 XMLHttpRequest 发送给它的请求处理以后须要某种指示说明怎么作。
在JS中引用函数
JavaScript 是一种弱类型的语言,能够用变量引用任何东西。所以若是声明了一个函数 updatePage(),JavaScript 也将该函数名看做是一个变量。换句话说,可用变量名updatePage在代码中引用函数。 如今onreadystatechange属性该登场了。该属性容许指定一个回调函数。回调容许服务器反向调用 Web 页面中的代码。它也给了服务器必定程度的控制权,当服务器完成请求以后,会查看XMLHttpRequest 对象,特别是onreadystatechange属性。而后调用该属性指定的任何方法。之因此称为回调是由于服务器向网页发起调用,不管网页自己在作什么。比方说,可能在用户坐在椅子上手没有碰键盘的时候调用该方法,可是也可能在用户输入、移动鼠标、滚动屏幕或者点击按钮时调用该方法。它并不关心用户在作什么。这就是称之为异步的缘由:用户在一层上操做表单,而在另外一层上服务器响应请求并触发 onreadystatechange 属性指定的回调方法。所以须要像以下同样在代码中指定该方法。
设置回调方法
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 属性设置为要运行的函数名。这样,当服务器处理完请求后就会自动调用该函数。也不须要担忧该函数的任何参数。咱们从一个简单的方法开始,回调方法的代码
<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 urljava
= "/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)。输入电话号码而后离开该字段,将看到一个弹出的警告窗口,可是点击 OK 又出现了……
根据浏览器的不一样,在表单中止弹出警告以前会看到两次、三次甚至四次警告。这是怎么回事呢?原来咱们尚未考虑 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,它表示服务器响应已经完成,能够安全地使用响应数据了。基于此,回调方法中的第一行应该以下检查就绪状态
function updatePage() {
if (request.readyState == 4)
alert("Server is done!");
}
修改后就能够保证服务器的处理已经完成。尝试运行新版本的Ajax代码,如今就会看到与预期的同样,只显示一次警告信息了。
HTTP 状态码
虽然代码看起来彷佛不错,可是还有一个问题——若是服务器响应请求并完成了处理可是报告了一个错误怎么办?要知道,服务器端代码应该明白它是由Ajax、JSP、普通HTML表单或其余类型的代码调用的,但只能使用传统的Web专用方法报告信息。而在Web世界中,HTTP代码能够处理请求中可能发生的各类问题。比方说,您确定遇到过输入了错误的 URL 请求而获得 404 错误码的情形,它表示该页面不存在。这仅仅是 HTTP 请求可以收到的众多错误码中的一种(完整的状态码请参阅相关资料)。表示所访问数据受到保护或者禁止访问的 403 和 401 也很常见。不管哪一种状况,这些错误码都是从完成的响应 获得的。换句话说,服务器履行了请求(即 HTTP 就绪状态是 4)可是没有返回客户机预期的数据。所以除了就绪状态外,还须要检查 HTTP 状态。咱们指望的状态码是 200,它表示一切顺利。若是就绪状态是 4 并且状态码是 200,就能够处理服务器的数据了,并且这些数据应该就是要求的数据(而不是错误或者其余有问题的信息)。所以还要在回调方法中增长状态检查,检查 HTTP 状态码。
function updatePage() {
if (request.readyState == 4)
if (request.status == 200)
alert("Server is done!");
}
为了增长更健壮的错误处理并尽可能避免过于复杂,能够增长一两个状态码检查,请看一看清单 15 中修改后的 updatePage() 版本。
增长一点错误检查
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 中的文本内容,好比格式和长度,有意保持含糊。这样服务器就能够将文本设置成任何内容。比方说,一种脚本可能返回逗号分隔的值,另外一种则使用管道符(即 | 字符)分隔的值,还有一种则返回长文本字符串。何去何从由服务器决定。在本文使用的例子中,服务器返回客户的上一个订单和客户地址,中间用管道符分开。而后使用订单和地址设置表单中的元素值,下面给出了更新显示内容的代码,处理服务器响应。
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并使用JS的split() 方法从管道符分开。获得的数组放到response中。数组中的第一个值——上一个订单——用 response[0] 访问,被设置为ID 为“order” 的字段的值。第二个值 response[1],即客户地址,则须要更多一点处理。由于地址中的行用通常的行分隔符(“\n”字符)分隔,代码中须要用 XHTML 风格的行分隔符 <br /> 来代替。替换过程使用 replace() 函数和正则表达式完成。最后,修改后的文本做为 HTML 表单 div 中的内部 HTML。程序员
responseXML属性
如今介绍XMLHttpRequest 的另外一个重要属性responseXML。若是服务器选择使用 XML 响应则该属性包含(也许您已经猜到)XML 响应。处理 XML 响应和处理普通文本有很大不一样,涉及到解析、文档对象模型(DOM)和其余一些问题。对于不少简单的 Ajax 应用程序 responseText 就够了,可是其实经过 Ajax 应用程序也能很好地处理 XML。web
结束语
您可能对XMLHttpRequest感到有点厌倦了,我不多看到一整篇文章讨论一个对象,特别是这种简单的对象。可是您将在使用Ajax编写的每一个页面和应用程序中反复使用该对象。坦白地说,关于 XMLHttpRequest 还真有一些可说的内容。其实有不少Ajax工具箱。这些工具箱实际上隐藏了本文所述的不少细节,使得 Ajax 编程更容易。您也许会想,既然有这么多工具箱为什么还要对底层的细节编码。答案是你若是不知道应用程序在作什么,就很难发现应用程序中的问题。所以不要忽略这些细节或者简单地浏览一下,若是便捷华丽的工具箱出现了错误,您就没必要挠头或者发送邮件请求支持了。若是了解如何直接使用 XMLHttpRequest,就会发现很容易调试和解决最奇怪的问题。只有让其解决您的问题,工具箱才是好东西。所以请熟悉 XMLHttpRequest 吧。事实上,若是您有使用工具箱的 Ajax 代码,能够尝试使用 XMLHttpRequest 对象及其属性和方法从新改写。这是一种不错的练习,能够帮助您更好地理解其中的原理。 正则表达式