乐途乐途
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
  • 学习路径
  • XML 基础语法

    • XML 概述
    • XML 文档结构
    • XML 元素
    • XML 属性
    • XML 语法规则
    • XML 命名空间
    • XML 注释与处理指令
  • DTD 与文档验证

    • DTD 概述
    • DTD 元素声明
    • DTD 属性声明
    • DTD 实体声明
    • DTD 元素与属性对比
    • DTD 完整示例
  • XML Schema 定义

    • XML Schema 概述
    • XSD 简单类型
    • XSD 复杂类型
    • XSD 命名空间与引用
  • XPath 节点定位

    • XPath 概述
    • XPath 路径表达式
    • XPath 谓词与函数
  • XSLT 转换

    • XSLT 概述
    • XSLT 模板与匹配
    • XSLT 控制结构
    • XSLT 输出控制
  • XML 解析技术

    • XML 解析概述
    • DOM 解析
    • SAX 解析
    • StAX 解析
    • XML 与 Java — JAXP
  • XML 在 Java 中的应用

    • Spring XML 配置
    • MyBatis XML 映射
    • pom.xml 与 Maven
    • web.xml 配置详解
  • 现代数据格式对比

    • XML 与 JSON 对比
    • XML 与 YAML 对比
  • XML 显示与浏览器集成

    • XML 在浏览器中的显示
    • XMLHttpRequest 与 AJAX
    • 服务器端 XML 处理
  • XML 进阶查询与链接

    • XQuery 查询语言
    • XLink 超链接
    • XML 验证工具使用
  • XML Web 服务(选读)

    • XML Web 服务概述
    • SOAP 协议详解
    • WSDL 服务描述
    • RSS 内容聚合
    • RDF 资源描述框架

XMLHttpRequest 与 AJAX

本章定位 :掌握 XMLHttpRequest 对象的核心机制——readyState 生命周期、responseXML 解析、异步回调模型,理解 AJAX 如何实现"无刷新更新页面"。

定义与作用

XMLHttpRequest (简称 XHR)是所有现代浏览器内置的一个 JavaScript 对象,用于在不刷新页面的情况下与服务器交换数据。它是 AJAX 技术的基石。

AJAX (Asynchronous JavaScript and XML)并非一种新技术,而是:

  • JavaScript 发起异步请求
  • XMLHttpRequest 对象作为通信载体
  • XML (或 JSON)作为数据交换格式
  • DOM 动态更新页面内容

四项技术的组合,让网页应用具备了"桌面应用般的流畅体验"。在 AJAX 出现之前,任何数据更新都需要整页刷新——这就像每次修改文档中的一个字都要把整本笔记本重新抄写一遍。

核心原理:XHR 生命周期

图解释 :XMLHttpRequest 对象经历 5 个 readyState 阶段(0→1→2→3→4)。每次状态变化都触发 onreadystatechange 回调。只有当 readyState=4 且 HTTP status=200 时,才表示服务器成功返回了完整数据。

语法/结构要点

XHR 核心属性与方法

属性/方法说明
readyState请求状态:0=UNSENT, 1=OPENED, 2=HEADERS_RECEIVED, 3=LOADING, 4=DONE
statusHTTP 状态码:200=成功, 404=未找到, 500=服务器错误
responseText以字符串形式返回服务器响应
responseXML以 XML DOM 对象形式返回服务器响应(Content-Type: text/xml 时才有值)
onreadystatechange状态变化时的回调函数
open(method, url, async)初始化请求:method=GET/POST, url=请求地址, async=true(异步)/false(同步)
send(data)发送请求。GET 请求传 null;POST 请求传请求体数据
setRequestHeader(name, value)设置 HTTP 请求头(必须在 open 之后、send 之前调用)

readyState 详解

readyState常量含义此时可用
0UNSENT对象已创建,open() 未调用无
1OPENEDopen() 已调用setRequestHeader()
2HEADERS_RECEIVED收到响应头status, getResponseHeader()
3LOADING正在接收响应体responseText(可能不完整)
4DONE响应完成responseText, responseXML(完整)

responseXML 的前提条件

responseXML 返回一个可被 DOM API 操作的 XML Document 对象,但需满足:

  1. 服务器响应的 Content-Type 必须是 text/xml 或 application/xml
  2. 服务器返回的 XML 必须是 格式良好 的(Well-Formed)
  3. 如果 XML 有语法错误,responseXML 将是 null

完整示例

场景说明

飞翔科技的前端 小崔 正在开发一个"项目进度查询"页面。产品经理要求在搜索框中输入项目 ID,页面需要实时显示该项目详情——不能刷新整个页面 。

后端已做好接口:GET /api/project?id=P001 返回 XML 格式的项目数据。

操作前:传统的整页刷新方式

<!-- 传统方式:form 提交导致整页刷新 -->
<form action="/api/project" method="get">
  <input type="text" name="id" placeholder="输入项目ID" />
  <button type="submit">查询</button>
</form>
<div id="result">
  <!-- 整页刷新后才能看到结果 -->
</div>

每次查询都要刷新页面,体验割裂。用户的滚动位置丢失、其他输入框内容清空。

应用 AJAX 后

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>飞翔科技 - 项目查询</title>
  <style>
    #result { margin-top: 20px; padding: 15px; border: 1px solid #ddd; }
    .loading { color: #ff9800; }
    .error { color: #f44336; }
  </style>
</head>
<body>
  <h2>项目进度查询</h2>
  <input type="text" id="projectId" placeholder="输入项目ID(如 P001)" />
  <button onclick="queryProject()">查询</button>

  <div id="result"></div>

  <script>
    function queryProject() {
      var id = document.getElementById("projectId").value.trim();
      if (!id) {
        document.getElementById("result").innerHTML
          = '<span class="error">请输入项目ID</span>';
        return;
      }

      var resultDiv = document.getElementById("result");
      resultDiv.innerHTML = '<span class="loading">查询中...</span>';

      // 1. 创建 XMLHttpRequest 对象
      var xhr = new XMLHttpRequest();

      // 2. 配置请求
      xhr.open("GET", "/api/project?id=" + encodeURIComponent(id), true);

      // 3. 设置回调 — 这是异步模型的核心
      xhr.onreadystatechange = function() {
        if (xhr.readyState === 4) {  // 响应完成
          if (xhr.status === 200) {   // HTTP 成功
            // 4. 解析 XML 响应
            var xmlDoc = xhr.responseXML;
            if (xmlDoc) {
              renderProject(xmlDoc, resultDiv);
            } else {
              resultDiv.innerHTML = '<span class="error">响应格式错误</span>';
            }
          } else if (xhr.status === 404) {
            resultDiv.innerHTML
              = '<span class="error">项目 ' + id + ' 不存在</span>';
          } else {
            resultDiv.innerHTML
              = '<span class="error">服务器错误(' + xhr.status + ')</span>';
          }
        }
      };

      // 5. 发送请求
      xhr.send(null);
    }

    function renderProject(xmlDoc, container) {
      // 使用 DOM API 从 XML 中提取数据
      var name = xmlDoc.getElementsByTagName("name")[0].textContent;
      var owner = xmlDoc.getElementsByTagName("owner")[0].textContent;
      var deadline = xmlDoc.getElementsByTagName("deadline")[0].textContent;
      var status = xmlDoc.getElementsByTagName("status")[0].textContent;
      var budget = xmlDoc.getElementsByTagName("budget")[0].textContent;

      var statusColor = status === "已完成" ? "#04AA6D"
        : status === "进行中" ? "#ff9800" : "#2196F3";

      container.innerHTML =
        '<table>' +
        '  <tr><td><strong>项目名称</strong></td><td>' + name + '</td></tr>' +
        '  <tr><td><strong>负责人</strong></td><td>' + owner + '</td></tr>' +
        '  <tr><td><strong>截止日期</strong></td><td>' + deadline + '</td></tr>' +
        '  <tr><td><strong>状态</strong></td>' +
        '      <td style="color:' + statusColor + ';font-weight:bold">'
        + status + '</td></tr>' +
        '  <tr><td><strong>预算</strong></td><td>¥' + budget + '</td></tr>' +
        '</table>';
    }
  </script>
</body>
</html>

服务器端返回的 XML 示例

当请求 GET /api/project?id=P001 时,服务器返回:

<?xml version="1.0" encoding="UTF-8"?>
<project id="P001">
  <name>智能工单系统</name>
  <owner>大翔</owner>
  <deadline>2026-05-15</deadline>
  <status>进行中</status>
  <budget>500000</budget>
</project>

操作结果

对比维度传统方式AJAX 方式
页面刷新整页刷新,闪烁、滚动丢失无刷新 ,页面保持原位
用户体验割裂感、等待白屏即时反馈,loading 提示流畅
其他输入所有表单输入丢失保留所有已填写内容
网络开销重新加载整个页面(HTML+CSS+JS)仅传输 XML 数据(几十字节)
可并发一次只能处理一个请求可同时发起多个异步请求

易错场景

在 readyState !== 4 时读取 responseXML

// 错误:可能拿到不完整数据
xhr.onreadystatechange = function() {
  var xml = xhr.responseXML;  // readyState=2/3 时可能为 null
  console.log(xml.getElementsByTagName("name"));  // TypeError!
};

正确 :始终先判断 xhr.readyState === 4 && xhr.status === 200。

混淆同步和异步模式

// 错误:第三个参数设为 false,变成同步请求
xhr.open("GET", url, false);
xhr.send(null);
// 此时 JS 线程被阻塞,页面卡死,直到响应返回

同步 XHR 已被主流浏览器标记为 废弃 。始终使用 true(异步模式),通过回调处理结果。

responseXML 为 null

这通常是因为服务器没有设置正确的 Content-Type:

// 后端忘记设置 Content-Type
response.getWriter().write(xmlString);  // 默认 text/html,responseXML 为 null

后端必须设置:response.setContentType("text/xml") 或 "application/xml"。

面试考点

考点参考答案要点
AJAX 的全称和四大组成部分?Asynchronous JavaScript and XML。JavaScript + XMLHttpRequest + XML/JSON 数据 + DOM 操作
readyState 的 5 个值及含义?0=UNSENT(未调用open), 1=OPENED(已调用open), 2=HEADERS_RECEIVED(收到响应头), 3=LOADING(接收中), 4=DONE(完成)
responseText 与 responseXML 的区别?responseText 返回字符串(适用任何响应类型);responseXML 返回 XML DOM 对象(仅当 Content-Type 为 XML 且格式良好时)
为什么同步 XHR 已被废弃?阻塞 JS 主线程导致页面卡死、用户体验极差。现代方案用 Promise/fetch 或 async/await
如何判断 AJAX 请求成功?readyState === 4 且 status 在 200~299 范围内
上一页
XML 在浏览器中的显示
下一页
服务器端 XML 处理