34、Ajax 开发实用指南

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 实现步骤

  1. 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>
  1. 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);
}
  1. 服务器端代码(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 应用程序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值