导读:本期聚焦于小鱼创作的《什么是Ajax中的XMLHttpRequest对象?如何用它实现异步请求?》,敬请观看详情。XMLHttpRequest是Ajax技术的核心对象,浏览器通过它可以在不刷新页面的情况下与服务器交换数据。本文从XMLHttpRequest的底层原理讲起,介绍它的创建方式、常用属性和方法,包括open、send、setRequestHeader的具体用法,并结合GET和POST两种请求方式给出完整代码示例。同时分析了readyState五种状态变化的含义、onreadystatechange事件的触发时机、status状态码的判断逻辑,以及跨域访问的限制和解决方案。文末还对比了XMLHttpRequest与fetch的优劣,帮助你判断在什么场景下该选择哪一种方案。

XMLHttpRequest是浏览器提供的一个JavaScript对象,也是Ajax技术得以实现的基础。在它出现之前,网页想要从服务器获取新数据,只能通过表单提交或者整页刷新,用户体验非常割裂。有了XMLHttpRequest之后,前端可以在后台悄悄向服务器发请求,拿到数据后再局部更新页面,这就是常说的异步无刷新交互。本文将围绕这个对象的创建、核心方法、状态监听以及常见问题展开讲解。

什么是Ajax中的XMLHttpRequest对象?如何用它实现异步请求?

一、XMLHttpRequest对象的创建与基本用法

创建XMLHttpRequest对象非常简单,现代浏览器中都支持通过new XMLHttpRequest()直接实例化。早年IE5和IE6需要借助ActiveXObject来创建,如今已无需兼容这种写法,但如果项目要维护老旧系统,还是建议做一层封装判断。

// 现代浏览器的标准创建方式
var xhr = new XMLHttpRequest();

// 兼容老版本IE的写法(仅维护老项目时需要)
var xhrOld = window.XMLHttpRequest
    ? new XMLHttpRequest()
    : new ActiveXObject("Microsoft.XMLHTTP");

对象创建之后,一个完整的请求流程分为四步:初始化请求、设置回调、发送请求、处理响应。初始化使用open方法,它接收三个参数,第一个是请求类型(GET或POST),第二个是请求地址,第三个是布尔值,true表示异步,false表示同步。需要特别注意的是,同步请求会阻塞JavaScript线程,浏览器控制台会直接给出弃用警告,实际开发中务必传true。

var xhr = new XMLHttpRequest();

// 第一步:初始化一个异步GET请求
xhr.open("GET", "https://ipipp.com/api/user?id=1001", true);

// 第二步:监听状态变化
xhr.onreadystatechange = function () {
    if (xhr.readyState === 4 && xhr.status === 200) {
        console.log("响应内容:", xhr.responseText);
    }
};

// 第三步:发送请求
xhr.send();

send方法的参数对于GET请求而言传null或者不传即可,因为GET请求的参数已经拼接在URL后面。而对于POST请求,send的参数就是请求体内容,通常是序列化后的表单字符串或者JSON字符串。

二、readyState状态机与onreadystatechange事件

XMLHttpRequest内部维护了一个状态机,readyState属性记录着当前请求处于哪个阶段,一共五个取值,理解它们对调试异步问题很有帮助。

  • 0(未初始化):对象已创建,但尚未调用open方法。
  • 1(已启动):open方法已调用,尚未调用send。
  • 2(已发送):send方法已调用,请求发出,但还没有收到响应。
  • 3(接收中):正在接收服务器返回的数据,responseText中是部分数据。
  • 4(完成):响应全部接收完毕,可以安全使用响应数据了。

onreadystatechange事件会在readyState每次变化时触发一次,所以一次完整请求中该回调会被触发多次。我们在回调里通常只关心readyState等于4的时刻,此时再结合status判断HTTP状态码,200到300之间(不含300)或者304都算成功。很多人只判断status为200,忽略了304缓存命中的情况,导致明明请求成功却走了错误分支,这是一个常见误区。

xhr.onreadystatechange = function () {
    console.log("当前状态:", xhr.readyState);
    if (xhr.readyState === 4) {
        if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
            // 成功:根据响应类型解析数据
            var data = JSON.parse(xhr.responseText);
            render(data);
        } else {
            console.error("请求失败,状态码:" + xhr.status);
        }
    }
};

另外,XMLHttpRequest还提供了更语义化的事件监听方式,比如onload在请求完成时触发,onerror在网络层错误时触发,ontimeout在超时时触发。这些事件比onreadystatechange更直观,新项目推荐使用,还可以配合timeout属性设置超时时间,避免请求无限挂起。

三、GET与POST请求的实战差异

GET请求把参数拼在URL后面,格式是?key1=value1&key2=value2,参数需要用encodeURIComponent编码,否则遇到中文或特殊字符会出错。GET请求有URL长度限制(浏览器实现各异,一般建议控制在2KB以内),且参数明文暴露在地址栏和服务器日志中,不适合传密码等敏感信息。

// GET请求:参数拼接在URL上
var page = 2;
var keyword = encodeURIComponent("前端教程");
xhr.open("GET", "https://ipipp.com/api/list?page=" + page + "&kw=" + keyword, true);
xhr.send();

POST请求则把数据放在请求体中,必须先用setRequestHeader设置Content-Type,告诉服务器请求体的格式。表单提交对应的是application/x-www-form-urlencoded,上传JSON对应application/json,如果忘了设置请求头,很多后端框架会解析不到参数,这是新手最常踩的坑之一。

var xhr = new XMLHttpRequest();
xhr.open("POST", "https://ipipp.com/api/login", true);

// 必须设置请求头,否则服务器无法识别请求体格式
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

xhr.onreadystatechange = function () {
    if (xhr.readyState === 4 && xhr.status === 200) {
        console.log(xhr.responseText);
    }
};

// 表单格式:键值对用 & 连接,值需要编码
xhr.send("username=admin&password=" + encodeURIComponent("123456"));

如果发送JSON数据,除了改Content-Type为application/json,send的参数要用JSON.stringify序列化,同时注意跨域场景下自定义的Content-Type可能触发预检请求(OPTIONS),服务器需要正确响应预检才能让正式请求通过。

四、跨域限制与XMLHttpRequest的局限

出于同源策略的安全限制,XMLHttpRequest默认只能请求与当前页面同协议、同域名、同端口的服务。一旦三者有任何一个不同,浏览器就会拦截响应并报跨域错误。需要澄清的是,请求其实已经发出去了,服务器也可能正常处理了,只是浏览器把响应挡在了JavaScript之外,所以这个问题无法只靠前端规避。

解决跨域的主流方案是CORS,即服务器在响应头中返回Access-Control-Allow-Origin等字段,明确声明允许哪些来源访问。前端这边XMLHttpRequest不需要特殊处理,浏览器会自动完成协议层面的协商。此外,JSONP利用<script>标签不受同源限制的特点实现跨域GET请求,但它只支持GET且安全性较差,如今已基本被CORS取代。

除了跨域,XMLHttpRequest还有一些固有局限:回调写法容易嵌套过深,代码可读性差;获取进度信息需要依赖onprogress事件,用法略显繁琐。因此现代浏览器推出了fetchAPI,它基于Promise,写法更简洁,配合async/await可以让异步代码接近同步的阅读体验。不过fetch不会在HTTP状态码为404、500时自动reject,需要手动检查response.ok,且默认不支持请求超时取消,这几点又不如XMLHttpRequest的timeout属性直接。两者并非替代关系,理解XMLHttpRequest的原理依然是掌握前端网络请求的必修课,因为Axios等主流库的底层在浏览器端依然构建在它之上。

XMLHttpRequestAjax异步请求修改时间:2026-09-04 00:58:53

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260904/49914.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。