原生 AJAX 揭秘:如何使用 XHR 发起请求
🚀 原生 AJAX 揭秘:如何使用 XHR 发起请求
🤔 什么是 XHR?
XMLHttpRequest是浏览器提供的一个内置对象,允许我们在后台与服务器交换数据。这意味着我们可以在不重新加载整个页面的情况下,更新网页的一部分。这就是著名的AJAX(Asynchronous JavaScript and XML) 技术的核心。
通俗比喻:
如果把浏览器比作一家餐厅:
- 传统页面刷新:你点完菜,必须离开餐厅,等厨房做好后,再重新进门坐下吃(整个页面重载)。
- XHR (AJAX):你坐在座位上,派服务员(XHR 对象)去厨房催菜或加菜。菜做好了,服务员直接端到你桌上(局部更新),你不需要离开座位。
📂 目录
- 🛠️ 发起请求的标准五步法
- 💻 代码实战:GET 与 POST
- 📊 核心概念:
readyState状态详解 - ⚠️ 常见陷阱与最佳实践
- 🔄 XHR vs Fetch:该选哪个?
- 💡 总结
1. 🛠️ 发起请求的标准五步法
使用 XHR 发起一个请求,通常遵循以下五个标准步骤。你可以把它当作一个模板来记忆。
第一步:创建对象
constxhr=newXMLHttpRequest();第二步:配置请求
使用open()方法初始化请求。
// open(method, url, async)xhr.open('GET','https://api.example.com/data',true);method: 请求类型 (GET,POST,PUT等)。url: 请求地址。async: 是否异步(默认为true,强烈建议保持异步,否则会阻塞页面)。
第三步:设置回调(监听状态变化)
在发送之前,先告诉 XHR:“当状态改变时,该做什么”。
xhr.onreadystatechange=function(){// 处理逻辑写在这里};第四步:发送请求
xhr.send();// GET 请求通常传 null 或不传// xhr.send(data); // POST 请求传入数据第五步:处理响应
在回调函数中,检查状态码并获取数据。
2. 💻 代码实战:GET 与 POST
场景一:发起 GET 请求
constxhr=newXMLHttpRequest();// 1. 配置xhr.open('GET','https://jsonplaceholder.typicode.com/todos/1',true);// 2. 监听状态xhr.onreadystatechange=function(){// readyState === 4 表示请求完成// status === 200 表示 HTTP 成功if(xhr.readyState===4&&xhr.status===200){console.log('请求成功!');console.log(JSON.parse(xhr.responseText));// 解析 JSON 数据}elseif(xhr.readyState===4){console.error('请求失败,状态码:',xhr.status);}};// 3. 发送xhr.send();场景二:发起 POST 请求(提交表单数据)
POST 请求通常需要设置请求头,并发送数据体。
constxhr=newXMLHttpRequest();// 1. 配置xhr.open('POST','https://jsonplaceholder.typicode.com/posts',true);// 2. 设置请求头(告诉服务器发送的是 JSON 格式)xhr.setRequestHeader('Content-Type','application/json;charset=UTF-8');// 3. 监听状态xhr.onreadystatechange=function(){if(xhr.readyState===4&&xhr.status===201){// 201 Createdconsole.log('创建成功!');console.log(JSON.parse(xhr.responseText));}};// 4. 发送数据constdata=JSON.stringify({title:'Foo',body:'Bar',userId:1});xhr.send(data);3. 📊 核心概念:readyState状态详解
xhr.readyState是一个整数,表示请求当前的阶段。理解它是处理异步逻辑的关键。
| 值 | 状态常量 | 含义 | 说明 |
|---|---|---|---|
| 0 | UNSENT | 未初始化 | 对象已创建,但未调用open() |
| 1 | OPENED | 已打开 | 已调用open(),但未调用send() |
| 2 | HEADERS_RECEIVED | 头已接收 | 已调用send(),且已接收到响应头 |
| 3 | LOADING | 加载中 | 响应体正在下载中(responseText已有部分数据) |
| 4 | DONE | 完成 | 整个请求过程结束,数据接收完毕 |
重点:
我们最关心的是readyState === 4。只有在这个状态下,xhr.responseText才是完整可用的。
4. ⚠️ 常见陷阱与最佳实践
❌ 陷阱 1:忘记检查 status
只判断readyState === 4是不够的。如果服务器返回 404 或 500,readyState也是 4,但请求实际上是失败的。
// ✅ 正确写法if(xhr.readyState===4){if(xhr.status>=200&&xhr.status<300){// 成功处理}else{// 错误处理}}❌ 陷阱 2:回调地狱与代码冗余
如果有多个请求依赖,XHR 的嵌套回调会让代码难以维护(Callback Hell)。
✅ 最佳实践:
在现代开发中,如果必须用原生 JS,建议将 XHR封装成 Promise,或者直接使用fetch。
// 封装成 Promise 的简单示例functionrequest(url){returnnewPromise((resolve,reject)=>{constxhr=newXMLHttpRequest();xhr.open('GET',url);xhr.onload=()=>{if(xhr.status===200)resolve(JSON.parse(xhr.responseText));elsereject(newError(xhr.statusText));};xhr.onerror=()=>reject(newError('Network Error'));xhr.send();});}// 使用 async/await 调用,代码更清晰asyncfunctiongetData(){try{constdata=awaitrequest('https://api.example.com/data');console.log(data);}catch(error){console.error(error);}}❌ 陷阱 3:跨域问题 (CORS)
XHR 同样受浏览器的同源策略限制。如果请求跨域接口,后端必须配置正确的 CORS 头(如Access-Control-Allow-Origin),否则前端会报错。
5. 🔄 XHR vs Fetch:该选哪个?
| 特性 | XMLHttpRequest(XHR) | fetchAPI |
|---|---|---|
| 出现时间 | 古老 (IE5 时代) | 现代 (ES6+) |
| 语法风格 | 基于事件回调 | 基于Promise |
| 代码简洁度 | 较繁琐 | 简洁优雅 |
| 错误处理 | 需手动检查 status | 网络错误才 reject,HTTP 错误需手动检查 |
| 进度监控 | ✅ 原生支持 (onprogress) | ❌ 需借助 ReadableStream (较复杂) |
| 兼容性 | ✅ 极好 (包括 IE) | ❌ IE 不支持 (需 polyfill) |
建议:
- 新项目:首选
fetch或axios。- 需要上传进度条:XHR 依然有优势,或者使用
axios(底层基于 XHR)。- 维护老项目/兼容 IE:必须掌握 XHR。
💡 总结
| 步骤 | 关键代码 | 作用 |
|---|---|---|
| 1. 创建 | new XMLHttpRequest() | 实例化对象 |
| 2. 配置 | xhr.open('GET', url) | 设定方法和地址 |
| 3. 监听 | xhr.onreadystatechange | 绑定状态变化回调 |
| 4. 发送 | xhr.send(body) | 发出请求 |
| 5. 判断 | readyState === 4 && status === 200 | 确认成功并处理数据 |
🚀 博主寄语:
虽然fetch是未来,但XHR是过去和现在的桥梁。
理解 XHR 的工作原理,能让你更深入地理解 HTTP 请求的生命周期、异步编程模型以及浏览器的网络机制。记住口诀:
新建对象 Open 配,
监听状态别嫌累。
Send 发送等回应,
四二零零才到位。
希望这篇文档能帮你彻底搞懂 XHR 请求!如果有疑问,欢迎在评论区留言。👇
喜欢这篇文章吗?记得点赞、收藏、转发哦!❤️
