Ajax 开发实用指南
1. 访问 XMLHttpRequest 对象
1.1 问题描述
想要访问 XMLHttpRequest 对象的实例。
1.2 解决方案
- 若不考虑对 IE6 的支持,可使用以下代码:
var xmlHttp = new XMLHttpRequest();
- 若必须支持 IE6 且未使用 JavaScript 库,则需使用以下跨浏览器代码:
if (window.XMLHttpRequest) {
xmlHttp = new XMLHttpRequest();
} else if (window.ActiveXObject) {
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
1.3 相关讨论
Microsoft 最初将 XMLHttpRequest 对象作为 ActiveX 对象发明。如今我们常用的 XMLHttpRequest 对象,即便在较新的 IE 版本中,也是独立发展而来。目前 W3C 正在努力对该对象进行标准化。
XMLHttpRequest 对象支持的客户端应用方法如下:
| 方法 | 描述 |
| ---- | ---- |
| open | 初始化请求,参数包括请求方法(GET 或 POST)、请求 URL、是否异步以及可能的用户名和密码,默认所有请求为异步发送。 |
| setRequestHeader | 设置请求的 MIME 类型。 |
| send | 发送请求。 |
| sendAsBinary | 发送二进制数据。 |
| abort | 中止已发送的请求。 |
| getResponseHeader | 检索响应头文本,若响应未返回或无响应头则返回 null。 |
| getAllResponseHeaders | 检索多部分请求的响应头文本。 |
此外,还有一个常用方法
overrideMimeType
未在上述列表中,因为它不属于 XMLHttpRequest 标准化过程,且有一家浏览器公司(Microsoft)不支持该方法。该方法通常用于覆盖服务器响应的 MIME 类型,示例如下:
xmlhttp.overrideMimeType('text/xml');
虽然缺乏对
overrideMimeType
的支持会带来不便,但并非无法解决。可以根据 MIME 类型处理数据,或确保服务器应用为数据设置正确的内容头。例如,在 PHP 应用中可使用以下代码确保客户端应用接收 XML 数据:
header("Content-Type: text/xml; charset=utf-8");
所有浏览器都支持的属性如下:
| 属性 | 描述 |
| ---- | ---- |
| status | 请求响应的 HTTP 结果状态。 |
| statusText | 服务器返回的响应文本。 |
| readyState | 请求的状态。 |
| responseText | 请求的基于文本的响应。 |
| responseXML | 请求的基于 XML 的 DOM 对象响应。 |
XMLHttpRequest 对象的一个主要限制是同源安全限制,即不能使用 XMLHttpRequest 向其他域的 API 发出服务请求。
2. 准备数据进行传输
2.1 问题描述
想要处理用于 Ajax 调用的表单数据,而非通过常规的表单提交过程发送数据。
2.2 解决方案
从表单字段或其他页面元素获取数据:
var state = document.getElementById("state").value;
若数据是用户输入的,如文本字段中的数据,需使用
encodeURIComponent
函数对结果进行编码,以转义文本中可能影响 Ajax 调用的字符:
var state = encodeURIComponent(document.getElementById("state").value);
对于单选按钮、复选框、下拉选择框或应用程序可控制数据的其他表单元素,无需对数据进行转义,因为可以确保这些值的格式正确。
2.3 相关讨论
根据操作类型,Ajax 调用的数据可能来自用户输入的文本,如文本字段中的内容。此时需要确保数据能在 Ajax 请求中使用,通过转义特定字符(如
&
、
+
和
=
)来实现。例如,字符串
This is $value3 @value &and ** ++ another
编码后为
This%20is%20%24value3%20%40value%20%26and%20**%20%2B%2B%20another
。
若 Ajax 请求为 POST 请求而非 GET 请求,则需要进一步编码,将空格编码为加号。可将此功能封装为可复用的函数:
function postEncodeURIComponent(str) {
str = encodeURIComponent(str);
return str.replace(/%20/g, "+");
}
转义操作可确保 Ajax 请求能成功通信,但不能保证请求的安全性。所有未知用户输入的数据都应进行清理,以防止 SQL 注入或跨站脚本(XSS)攻击。不过,这种安全处理应在服务器端应用中实现,因为如果用户能在 JavaScript 中构造 GET 请求,也能直接在浏览器地址栏中构造 GET 请求,从而绕过脚本。只有在计划将用户数据直接嵌入页面时,才需要在 JavaScript 中对输入进行清理。
3. 确定查询调用类型
3.1 问题描述
不确定是将 Ajax 调用作为 GET 还是 POST 请求发送。
3.2 解决方案
-
更新操作
:发送 POST 请求,将 XMLHttpRequest 的
open方法的第一个参数设置为POST,调用setRequestHeader设置内容类型,并在send方法中发送请求参数:
xmlhttp.open('POST', url, true);
xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlhttp.send(param);
-
查询操作
:发送 GET 请求,将 XMLHttpRequest 的
open方法的第一个参数设置为GET,将参数附加到请求 URL 上,并在send方法中传递null:
url = url + "?" + param;
xmlhttp.open('GET', url, true);
xmlhttp.send(null);
3.3 相关讨论
应用程序的服务器组件的期望对请求类型的决策影响最大。不过,通常的做法是,获取数据的请求使用 GET,而更新操作使用 POST。
Ajax 中使用的请求类型实践源自 RESTful 准则(REST 即 REpresentational State Transfer)。根据该准则,HTTP 请求有四种类型:
| 请求类型 | 描述 |
| ---- | ---- |
| GET | 用于检索信息,参数附加到 URL 上。 |
| POST | 用于创建新数据,参数通过函数参数发送。 |
| DELETE | 用于删除数据记录,参数通过函数参数发送。 |
| PUT | 用于发送更新,参数通过函数参数发送。 |
目前广泛支持的只有 GET 和 POST 请求,下面分别给出示例代码:
-
GET 请求示例
:
function sendData(evt) {
// 取消默认表单提交
evt = evt || window.event;
evt.preventDefault();
evt.returnValue = false;
// 获取输入数据
var one = encodeURIComponent(document.getElementById("one").value);
var two = encodeURIComponent(document.getElementById("two").value);
var params = "one=" + one + "&two=" + two;
// 准备请求
if (!http) {
http = new XMLHttpRequest();
}
var url = "ajaxserver.php?" + params;
http.open("GET", url, true);
// 回调函数
http.onreadystatechange = processResult;
// 发起带参数的 Ajax 调用
http.send(null);
}
- POST 请求示例 :
function sendData(evt) {
// 取消默认表单提交
evt = evt || window.event;
evt.preventDefault();
evt.returnValue = false;
// 获取输入数据
var one = encodeURIComponent(document.getElementById("one").value).replace(/%20/g, '+');
var two = encodeURIComponent(document.getElementById("two").value).replace(/%20/g, '+');
var params = "one=" + one + "&two=" + two;
// 准备请求
if (!http) {
http = new XMLHttpRequest();
}
var url = "ajaxserver.php";
http.open("POST", url, true);
// 设置 Ajax 头
http.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
http.setRequestHeader("Content-length", params.length);
http.setRequestHeader("Connection", "close");
// 回调函数
http.onreadystatechange = processResult;
// 发起带参数的 Ajax 调用
http.send(params);
}
POST 请求代码与 GET 请求代码的不同之处在于:编码后,参数中的空格从
%20
转换为
+
;参数被拼接成参数格式的字符串,并在
send
方法中发送。
open
方法的第一个参数设置为
POST
,但其他两个参数(应用程序 URL 和异步标志)与 GET 请求相同。此外,还会调用
setRequestHeader
方法设置
Connection
和
Content-length
请求头,必须为 POST 请求提供
Content-Type
。
两种请求方式都会为 Ajax 对象调用的
onreadystatechange
事件处理程序设置回调函数。
4. 为 Ajax 请求添加回调函数
4.1 问题描述
想要处理 Ajax 请求的结果,即使结果是更新操作而非查询操作。
4.2 解决方案
在处理 Ajax 请求时,调用 XMLHttpRequest 对象的
send
方法之前,将对象的
onreadystatechange
属性赋值为回调函数的名称:
xmlhttp.open("GET", url, true);
xmlhttp.onreadystatechange = callbackFunction;
xmlhttp.send(null);
4.3 相关讨论
XMLHttpRequest 对象的
readyState
属性会根据请求状态进行更新。为了检查请求状态,需要将
onreadystatechange
事件处理程序赋值给一个回调函数,该函数会在请求状态每次改变时被调用。
每次 Ajax 调用都应使用
onreadystatechange
,即使是更新操作而非请求处理。没有回调函数,就无法知道更新操作是否成功,以及如果失败,发生了哪种类型的错误。
readyState
属性在 Ajax 请求期间的值如下:
| 值 | 状态 | 用途 |
| ---- | ---- | ---- |
| 0 | UNINITIALIZED |
open
方法尚未调用 |
| 1 | LOADING |
send
方法尚未调用 |
| 2 | LOADED |
send
方法已调用 |
| 3 | INTERACTIVE | 响应下载未完成 |
| 4 | COMPLETED | 请求完成 |
如果请求是同步的,则不应设置
onreadystatechange
,因为代码会在请求返回之前一直等待,可以在代码的下一行检查操作结果。强烈建议避免使用同步 Ajax 调用,因为在请求完成之前锁定页面不是一个好的做法。
5. 检查错误条件
5.1 问题描述
想要检查 Ajax 请求的状态。
5.2 解决方案
在
onreadystatechange
事件处理程序中,除了检查
readyState
属性,还可以检查 XMLHttpRequest 的
status
属性:
function processResult() {
if (http.readyState == 4 && http.status == 200) {
document.getElementById("result").innerHTML = http.responseText;
}
}
5.3 相关讨论
XMLHttpRequest 的
status
属性返回请求的响应状态。期望的状态码是 200,表示请求成功。如果状态码是其他值,如 403(禁止访问)或 500(服务器错误),可以访问 XMLHttpRequest 的
statusText
属性获取更详细的信息:
function processResult() {
if (http.readyState == 4 && http.status == 200) {
document.getElementById("result").innerHTML = http.responseText;
} else {
alert(http.statusText);
}
}
6. 处理文本结果
6.1 问题描述
想要处理以文本形式返回的 HTML。
6.2 解决方案
如果信任服务器应用程序,且文本格式可直接在页面中使用,最简单的方法是将文本赋值给要放置该文本的元素的
innerHTML
属性:
function processResult() {
if (http.readyState == 4 && http.status == 200) {
document.getElementById("result").innerHTML = http.responseText;
}
}
6.3 相关讨论
如果同时编写应用程序的服务器端和客户端,应尽量简化处理。在服务器应用程序中对响应进行格式化,以便使用最简单的方法将其添加到网页中,而
innerHTML
是最简单的方法之一。
然而,如果响应文本未针对直接发布进行格式化,则需要使用字符串函数,可能结合正则表达式,来提取所需的数据。如果无法或不希望进行 HTML 格式化,且对服务器应用程序有一定控制权,可以尝试将其格式化为 XML 或 JSON,这两种格式在 JavaScript 环境中更容易处理。
7. 跨域进行 Ajax 请求(使用 JSONP)
7.1 问题描述
想要使用 Web 服务 API(如 Netflix API 或 Twitter API)查询数据,但 Ajax 的同源策略阻止了跨域通信。
7.2 解决方案
- 服务器端代理应用 :最常用的解决跨域问题的方法是创建一个服务器端代理应用,在 Ajax 应用中调用该代理,代理再调用其他服务的 API,并将结果返回给客户端应用。这种方法安全、可靠且高效,因为可以在将数据返回给 Ajax 应用之前对其进行清理。
- JSONP :另一种方法是使用 JSONP(JSON with Padding)来绕过安全问题。例如,曾使用该方法创建 Google Maps 和 Flickr 查询结果的混搭:
function addScript(url) {
var script = document.createElement('script');
script.type = "text/javascript";
script.src = url;
document.getElementsByTagName('head')[0].appendChild(script);
}
请求的 URL 如下,包括返回 JSON 格式数据的请求和提供的回调函数名:
http://api.flickr.com/services/rest/?method=flickr.photos.search&user_id=xxx&api_key=xxx&format=json&jsoncallback=processPhotos
创建脚本标签时,会向 Flickr 发出请求。由于请求返回 JSON 格式的数据并提供了回调函数名,返回的数据会以这种方式提供。回调函数示例如下:
// 全局分配照片,先调用以加载
function processPhotos(obj) {
photos = obj.photos.photo;
...
}
回调函数会将格式化为 JSON 对象的数据作为函数参数传递。
7.3 相关讨论
Ajax 在受保护的环境中工作,可确保不会因调用外部应用程序(可能安全也可能不安全)而将危险文本或代码嵌入网页。但这种安全性的缺点是无法直接访问外部 API 服务,如 Flickr、Twitter 和 Google。因此需要创建服务器端代理应用,因为服务器应用不受跨域限制。
JSONP 是一种绕过安全问题的方法,它将请求 URL 转换为可以附加到脚本
src
属性的形式,因为脚本元素不受同源策略限制。如果服务支持,会返回 JSON 格式的数据,甚至将其包装在回调函数中。创建脚本时,就像直接在代码中调用函数并传递对象作为参数一样,无需担心将字符串转换为 JavaScript 对象。
虽然这是一个巧妙的技巧,但不建议使用。即使是像 Flickr 和 Twitter 这样的安全服务,也存在有人通过服务的客户端应用将 JavaScript 注入数据的可能性,从而对自己的应用程序造成破坏。更明智的做法是使用代理应用,清理结果,然后将其传递给客户端应用。
8. 从服务器填充选择列表
8.1 问题描述
根据用户对另一个表单元素的操作,想要用值填充选择列表。
8.2 解决方案
-
捕获触发表单元素的
change事件:
document.getElementById("nicething").onchange = populateSelect;
- 在事件处理函数中,使用表单数据进行 Ajax 调用:
var url = "nicething.php?nicething=" + value;
xmlhttp.open('GET', url, true);
xmlhttp.onreadystatechange = getThings;
xmlhttp.send(null);
- 在 Ajax 结果函数中,填充选择列表:
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
var select = document.getElementById("nicestuff");
select.length = 0;
var nicethings = xmlhttp.responseText.split(",");
for (var i = 0; i < nicethings.length; i++) {
select.options[select.length] = new Option(nicethings[i], nicethings[i]);
}
select.style.display = "block";
} else if (xmlhttp.readyState == 4 && xmlhttp.status != 200) {
// 处理错误情况
}
8.3 相关讨论
通过捕获表单元素的
change
事件,触发 Ajax 请求从服务器获取数据,并将数据填充到选择列表中。在填充列表之前,先清空列表,然后将服务器返回的响应文本按逗号分割成数组,遍历数组并为选择列表添加选项。如果请求成功,将选择列表显示出来;如果请求失败,则可以根据具体情况处理错误。
综上所述,在 Ajax 开发中,我们需要掌握 XMLHttpRequest 对象的使用、数据的准备和编码、请求类型的选择、回调函数的添加、错误检查、结果处理、跨域请求的解决方法以及动态填充页面元素等关键技术,以实现高效、安全的 Web 应用程序。
8.4 流程图展示
下面是一个 mermaid 格式的流程图,展示了从服务器填充选择列表的整个流程:
graph TD;
A[用户操作触发表单元素 change 事件] --> B[调用 populateSelect 函数];
B --> C[构造请求 URL];
C --> D[初始化 XMLHttpRequest 对象];
D --> E[设置请求方法、URL 和异步标志];
E --> F[设置 onreadystatechange 事件处理函数];
F --> G[发送请求];
G --> H{请求是否完成且状态码为 200};
H -- 是 --> I[清空选择列表];
I --> J[分割响应文本为数组];
J --> K[遍历数组添加选项到选择列表];
K --> L[显示选择列表];
H -- 否 --> M[处理错误情况];
8.5 总结
从服务器填充选择列表是一个常见的 Web 开发需求,通过 Ajax 技术可以实现动态更新选择列表,提升用户体验。在实现过程中,需要注意事件的捕获、请求的发送、响应的处理以及错误的处理等环节。
9. 综合应用案例
9.1 案例描述
假设我们要开发一个简单的用户信息查询系统,用户在输入框中输入用户名,点击查询按钮后,通过 Ajax 请求从服务器获取该用户的详细信息,并将信息显示在页面上。
9.2 实现步骤
- HTML 结构 :创建一个包含输入框、查询按钮和结果显示区域的 HTML 页面。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户信息查询系统</title>
</head>
<body>
<input type="text" id="username" placeholder="请输入用户名">
<button onclick="queryUserInfo()">查询</button>
<div id="result"></div>
<script src="script.js"></script>
</body>
</html>
-
JavaScript 代码
:在
script.js文件中实现 Ajax 请求和结果处理逻辑。
function queryUserInfo() {
// 获取用户输入的用户名
var username = document.getElementById("username").value;
// 编码用户名
var encodedUsername = encodeURIComponent(username);
// 构造请求 URL
var url = "userinfo.php?username=" + encodedUsername;
// 创建 XMLHttpRequest 对象
var xmlhttp;
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
} else {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
// 设置请求方法、URL 和异步标志
xmlhttp.open("GET", url, true);
// 设置回调函数
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
// 处理响应结果
document.getElementById("result").innerHTML = xmlhttp.responseText;
} else if (xmlhttp.readyState == 4 && xmlhttp.status != 200) {
// 处理错误情况
alert("请求出错:" + xmlhttp.statusText);
}
};
// 发送请求
xmlhttp.send(null);
}
-
服务器端代码(PHP 示例)
:在
userinfo.php文件中处理请求并返回用户信息。
<?php
// 获取请求参数
$username = $_GET['username'];
// 模拟查询数据库获取用户信息
$userInfo = "用户 " . $username . " 的详细信息:这是一个模拟的用户信息。";
// 设置响应头
header("Content-Type: text/html; charset=utf-8");
// 返回响应结果
echo $userInfo;
?>
9.3 代码解释
- HTML 部分 :提供了用户输入用户名和触发查询的界面,以及显示查询结果的区域。
- JavaScript 部分 :
- 获取用户输入的用户名并进行编码。
- 构造请求 URL,使用 GET 请求方式。
- 创建 XMLHttpRequest 对象,设置请求方法、URL 和异步标志。
-
设置
onreadystatechange回调函数,处理请求状态的变化和响应结果。 - 发送请求。
- PHP 部分 :
- 获取请求参数。
- 模拟查询数据库获取用户信息。
- 设置响应头,确保返回的信息编码正确。
- 返回用户信息。
9.4 注意事项
- 数据安全 :在实际应用中,需要对用户输入的数据进行严格的验证和过滤,防止 SQL 注入和 XSS 攻击。
- 错误处理 :在 JavaScript 中,要对请求的不同状态进行处理,确保用户能够得到明确的错误提示。
- 跨域问题 :如果服务器和客户端不在同一个域名下,需要考虑跨域问题,可以使用前面提到的服务器端代理或 JSONP 等方法解决。
10. 性能优化建议
10.1 减少请求次数
- 合并请求 :将多个相关的请求合并为一个请求,减少网络开销。例如,如果需要同时获取用户的基本信息和订单信息,可以在服务器端将这两个信息合并后返回。
- 缓存数据 :对于一些不经常变化的数据,可以在客户端或服务器端进行缓存。例如,用户的个人资料信息可以在客户端缓存一段时间,避免每次都向服务器发送请求。
10.2 优化请求数据
- 压缩数据 :在服务器端对返回的数据进行压缩,减少数据传输量。例如,使用 Gzip 压缩可以显著减少数据大小。
- 只请求必要的数据 :在设计 API 时,只返回客户端需要的数据,避免返回过多的冗余数据。
10.3 异步请求的优化
- 合理设置超时时间 :为 XMLHttpRequest 请求设置合理的超时时间,避免长时间等待无响应的请求。
- 并发请求的控制 :如果需要同时发送多个异步请求,要控制并发请求的数量,避免对服务器造成过大的压力。
10.4 性能优化总结
性能优化是 Web 开发中非常重要的一环,通过减少请求次数、优化请求数据和异步请求的处理,可以提高应用程序的响应速度和用户体验。
11. 总结与展望
11.1 总结
本文详细介绍了 Ajax 开发中的多个关键技术,包括 XMLHttpRequest 对象的访问、数据的准备和传输、请求类型的选择、回调函数的添加、错误检查、结果处理、跨域请求的解决方法以及动态填充页面元素等。通过实际的代码示例和案例,展示了如何将这些技术应用到实际开发中。同时,还提供了性能优化的建议,帮助开发者提高 Web 应用程序的性能和用户体验。
11.2 展望
随着 Web 技术的不断发展,Ajax 仍然是实现动态 Web 应用的重要技术之一。未来,我们可以期待更多的优化和改进,例如更好的跨域解决方案、更高效的请求处理机制以及与其他新兴技术的结合。同时,随着前端框架的不断发展,如 React、Vue.js 等,Ajax 技术也将与这些框架更好地集成,为开发者提供更便捷、高效的开发体验。
在实际开发中,开发者需要根据具体的需求和场景,灵活运用这些技术,不断探索和创新,以实现更加优秀的 Web 应用程序。
超级会员免费看
1447

被折叠的 条评论
为什么被折叠?



