在 Web 的早期岁月里,页面与服务器的交互是一种 "粗暴" 的全页刷新模式。用户的每一次操作,无论是提交表单还是点击链接,都意味着浏览器要丢弃当前的一切,重新加载一个全新的页面。这种模式不仅体验糟糕,也造成了大量不必要的数据传输。
直到 XMLHttpRequest 对象的出现,这一切才得以改变。它就像一位隐形的信使 ,能够在不打扰用户、不刷新页面的情况下,悄悄地在浏览器与服务器之间穿梭,传递数据。这便是我们熟知的 AJAX (Asynchronous JavaScript and XML)技术的核心。正是这位信使,构建起了前端与后端之间的数据桥梁,催生了现代富交互 Web 应用(Rich Internet Application)的繁荣。

一、创建与兼容性
要派遣这位信使,首先需要在 JavaScript 中创建它的实例。
javascript
let xhr;
// 现代浏览器的标准方式
xhr = new XMLHttpRequest();
然而,在 Web 发展的长河中,总有一些历史的包袱需要背负。对于古老的 IE6 及以下浏览器,它们并不认识 XMLHttpRequest,我们需要通过一个不同的 "咒语" 来召唤它 ------ActiveXObject。
javascript
// 兼容旧版 IE 的方式
xhr = new ActiveXObject('Microsoft.XMLHTTP');
因此,一个健壮的 "召唤仪式" 通常会结合这两种方式,并使用 try...catch 来捕获可能的错误,确保在不同的浏览器环境下都能成功创建信使。
javascript
function createXHR() {
let xhr;
try {
// 尝试召唤现代信使
xhr = new XMLHttpRequest();
} catch (e) {
try {
// 如果失败,尝试召唤旧版 IE 的信使
xhr = new ActiveXObject('Microsoft.XMLHTTP');
} catch (e2) {
// 如果所有尝试都失败,则说明浏览器过于古老
xhr = null;
alert('您的浏览器不支持 AJAX,请升级!');
}
}
return xhr;
}
const xhr = createXHR();
if (xhr) {
// 信使已就绪,可以开始执行任务
}
二、核心方法
一旦信使(xhr 对象)被成功创建,我们就需要为它规划任务。这主要通过几个核心方法来完成。
open(method, url, async, [user], [password]):规划行程
这个方法用于初始化一个请求,但它并不会立即发送。它更像是在给信使下达任务指令:
method: 请求的 "交通方式",通常是GET或POST。GET用于从服务器获取数据,POST用于向服务器提交数据。url: 请求的 "目的地",即服务器上的接口地址,可以是相对路径或绝对路径。async: 是否采用 "异步" 方式。这是 AJAX 的灵魂所在。true(默认): 异步请求。信使出发后,主线程(浏览器)不会等待,而是继续执行后续代码。当信使带回数据后,会通过回调函数通知主线程。这保证了页面的流畅性。false: 同步请求。主线程会一直等待,直到信使完成任务并返回数据。在此期间,页面会 "冻结",用户无法进行任何操作。这种方式现在已不被推荐。
user,password: 可选参数,用于需要身份验证的请求。
javascript
// 初始化一个异步的 GET 请求
xhr.open('GET', 'https://api.example.com/data', true);
setRequestHeader(header, value):准备 "通关文牒"
在发送请求前,有时需要为信使准备一些特殊的 "通关文牒",也就是 HTTP 请求头。
-
当使用
POST方法提交表单数据时,必须告诉服务器我们发送的数据格式:javascriptxhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); -
还可以设置其他头信息,例如接受的数据类型、Cookie 等。
这个方法必须在 open() 之后、send() 之前调用。
send(body):派遣信使
这是真正发送请求 的方法。它会将请求打包并发送到 open() 方法指定的 URL。
body: 要发送给服务器的数据主体。- 对于
GET请求,数据通常通过 URL 的查询字符串(?key=value)发送,因此send()方法的参数应为null。 - 对于
POST请求,数据通过请求体(body)发送。你需要将数据拼接成字符串(如'username=admin&password=123')或传递一个FormData对象。
- 对于
javascript
// 发送 GET 请求
xhr.send(null);
// 发送 POST 请求
const postData = 'username=admin&password=123';
xhr.open('POST', 'https://api.example.com/login', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send(postData);
发送异步请求后,send() 方法会立即返回,程序继续执行。
abort():召回信使
在某些情况下(例如用户点击了 "取消" 按钮,或请求超时),你可能需要中途取消一个正在进行的请求。
javascript
// 取消当前请求
xhr.abort();
调用后,xhr 对象的 readyState 会重置为 0(未初始化),请求被终止。
三、 核心属性与事件
对于异步请求,我们无法预知信使何时能返回。因此,我们需要一种机制来 "监听" 它的旅程状态。
readyState:信使的行程状态
xhr.readyState 属性用来表示 请求 / 响应过程的当前活动阶段 。它的值从 0 变化到 4。
0(UNSENT): 请求未初始化。open()方法尚未被调用。1(OPENED):open()方法已调用,但send()方法尚未调用。可以设置请求头。2(HEADERS_RECEIVED):send()方法已调用,服务器的响应头和状态码已收到。3(LOADING): 正在接收服务器返回的响应主体(response body)。数据可能还未完全接收完毕。4(DONE): 请求已完成,响应数据已完全接收。
onreadystatechange:状态变化的 "警报器"
这是一个事件处理函数 。每当 readyState 属性的值发生变化时,浏览器就会触发这个事件。这是我们处理异步响应的核心。
我们通常会在这里检查 readyState 是否为 4(请求完成),并进一步检查 HTTP 状态码是否为 200(成功)。
javascript
xhr.onreadystatechange = function() {
// 当请求完成 (readyState === 4) 且响应成功 (status === 200)
if (xhr.readyState === 4 && xhr.status === 200) {
// 在这里处理服务器返回的数据
console.log('请求成功!');
const responseData = xhr.responseText; // 获取文本形式的响应
// ...
} else if (xhr.readyState === 4) {
// 请求完成但失败
console.error('请求失败,状态码:', xhr.status);
}
};
status:服务器的 "回信状态"
xhr.status 属性返回服务器响应的 HTTP 状态码。这是判断请求是否成功的关键。
200 OK: 请求成功。304 Not Modified: 请求的资源未被修改,可以使用浏览器缓存。400 Bad Request: 客户端请求有语法错误。401 Unauthorized: 请求要求用户身份验证。403 Forbidden: 服务器拒绝执行请求。404 Not Found: 请求的资源不存在。500 Internal Server Error: 服务器内部发生错误。
responseText 与 responseXML:信使带回的 "信物"
当请求成功后,服务器返回的数据就是信使带回的 "信物",可以通过以下两个属性获取:
xhr.responseText: 以字符串 形式返回响应数据。这是最常用的方式,返回的通常是 JSON 格式的字符串,需要用JSON.parse()解析。xhr.responseXML: 如果服务器返回的是格式正确的 XML 文档,该属性会返回一个 XML DOM 对象,可以使用 DOM 方法来操作。
getResponseHeader() 与 getAllResponseHeaders():查看 "回执"
这两个方法用于获取服务器响应头的信息,相当于查看信使带回的 "回执"。
xhr.getResponseHeader('Content-Type'): 获取指定名称的响应头的值。xhr.getAllResponseHeaders(): 获取所有响应头信息,以字符串形式返回。
最后小结:
XMLHttpRequest 对象是 Web 开发中一个里程碑式的存在。它打破了传统 Web 应用的交互模式,通过异步数据交换,极大地提升了用户体验,是构建现代单页应用(SPA)和动态网站的基石。
尽管如今 fetch API 和 axios 等更现代、更友好的库在很大程度上取代了 XMLHttpRequest 的直接使用,但理解它的工作原理 ------ 从创建实例、初始化请求、发送数据,到监听状态变化、处理响应 ------ 对于每一位前端开发者来说,都是深入理解 Web 通信本质的必经之路。这位 "老派" 的隐形信使,依然在幕后影响着我们每天使用的无数 Web 应用。