技术演进中的开发沉思-220 Ajax:XMLHttpRequest 对象

在 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 : 请求的 "交通方式",通常是 GETPOSTGET 用于从服务器获取数据,POST 用于向服务器提交数据。
  • url: 请求的 "目的地",即服务器上的接口地址,可以是相对路径或绝对路径。
  • async : 是否采用 "异步" 方式。这是 AJAX 的灵魂所在。
    1. true (默认): 异步请求。信使出发后,主线程(浏览器)不会等待,而是继续执行后续代码。当信使带回数据后,会通过回调函数通知主线程。这保证了页面的流畅性。
    2. false: 同步请求。主线程会一直等待,直到信使完成任务并返回数据。在此期间,页面会 "冻结",用户无法进行任何操作。这种方式现在已不被推荐。
  • user, password: 可选参数,用于需要身份验证的请求。
javascript 复制代码
// 初始化一个异步的 GET 请求
xhr.open('GET', 'https://api.example.com/data', true);
setRequestHeader(header, value):准备 "通关文牒"

在发送请求前,有时需要为信使准备一些特殊的 "通关文牒",也就是 HTTP 请求头。

  • 当使用 POST 方法提交表单数据时,必须告诉服务器我们发送的数据格式:

    javascript 复制代码
    xhr.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: 服务器内部发生错误。
responseTextresponseXML:信使带回的 "信物"

当请求成功后,服务器返回的数据就是信使带回的 "信物",可以通过以下两个属性获取:

  • xhr.responseText : 以字符串 形式返回响应数据。这是最常用的方式,返回的通常是 JSON 格式的字符串,需要用 JSON.parse() 解析。
  • xhr.responseXML : 如果服务器返回的是格式正确的 XML 文档,该属性会返回一个 XML DOM 对象,可以使用 DOM 方法来操作。
getResponseHeader()getAllResponseHeaders():查看 "回执"

这两个方法用于获取服务器响应头的信息,相当于查看信使带回的 "回执"。

  • xhr.getResponseHeader('Content-Type'): 获取指定名称的响应头的值。
  • xhr.getAllResponseHeaders(): 获取所有响应头信息,以字符串形式返回。

最后小结:

XMLHttpRequest 对象是 Web 开发中一个里程碑式的存在。它打破了传统 Web 应用的交互模式,通过异步数据交换,极大地提升了用户体验,是构建现代单页应用(SPA)和动态网站的基石。

尽管如今 fetch APIaxios 等更现代、更友好的库在很大程度上取代了 XMLHttpRequest 的直接使用,但理解它的工作原理 ------ 从创建实例、初始化请求、发送数据,到监听状态变化、处理响应 ------ 对于每一位前端开发者来说,都是深入理解 Web 通信本质的必经之路。这位 "老派" 的隐形信使,依然在幕后影响着我们每天使用的无数 Web 应用。

相关推荐
IT_陈寒1 小时前
Python开发者必看:5个被低估但能提升200%编码效率的冷门库实战
前端·人工智能·后端
g***78911 小时前
鸿蒙NEXT(五):鸿蒙版React Native架构浅析
android·前端·后端
q***71851 小时前
Webpack、Vite区别知多少?
前端·webpack·node.js
千里念行客2401 小时前
国产射频芯片“小巨人”昂瑞微今日招股 拟于12月5日进行申购
大数据·前端·人工智能·科技
小杨快跑~2 小时前
Vue 3 + Element Plus 表单校验
前端·javascript·vue.js·elementui
我叫张小白。3 小时前
Vue3监视系统全解析
前端·javascript·vue.js·前端框架·vue3
WYiQIU8 小时前
11月面了7.8家前端岗,兄弟们12月我先躺为敬...
前端·vue.js·react.js·面试·前端框架·飞书
谢尔登8 小时前
简单聊聊webpack摇树的原理
运维·前端·webpack
娃哈哈哈哈呀8 小时前
formData 传参 如何传数组
前端·javascript·vue.js