还在 XHR、Fetch 和 Axios 之间纠结?我踩过的坑,希望你一个都不用碰到

各位老铁是不是在每次新起一个前端项目时,都要在 fetchaxios 之间纠结半天?

或者面试时,对于面试官总爱问的"Ajax 和 Fetch 有啥区别",明明都会用,却说不出个所以然?

之前我在 async/await 里手动解析 fetch 的 JSON,被同事看到后,反问我"为什么要写这么多行",那尴尬劲......

今天打算花些时间,必须把这事儿掰扯明白。

这篇文章能帮你解决

搞清楚 XHR、Ajax、jQuery 封装、Fetch、Axios 的本质关系,看懂它们是个啥,以及各自的适用场景,最后能在心里有一份可以直接在项目里参考的选型指南。

这里先说明一点,Ajax不是一个具体的API,而是一种思想,一种实现局部刷新的思想!

要实现Ajax,你可以用XHR,也可以用Fetch等!

好啦,正文开始!

主要内容脉络

先从那个"上古时代"的 XHR 聊起,再盘一盘 jQuery 是怎么当保姆的,

接着咱们重点吐槽一下 Fetch 那些让人防不胜防的大坑,

最后说说为什么 Axios 成了我现在的"首选方案"。

分析的时候,我尽量给每个场景都配上代码对比,咱主打一个无痛学习。
👩‍💻我是爱折腾的一名程序媛 ,喜欢研究全栈开发 的各种实践,热爱分享踩坑后的收获与思考 ,也享受用代码写出各种实用小工具解决问题的快乐。

如果你也在技术这条路上向前走,关注我,愿我们能彼此陪伴,一起成为更好的自己 🌱

🤔 那个又爱又恨的"底座":XHR

好,咱们先来认识一下所有现代请求方案的祖宗------XMLHttpRequest,简称 XHR。

你别看它名字里带 XML,其实早跟 XML 没啥关系了,现在清一色的前后端传输数据都用 JSON 了。

怎么说呢?我的理解是,它的工作方式特别像你打电话到银行办业务

咱们一般都是先拨号 xhr.open('GET', url)

然后对着话筒说我要办啥啥业务 xhr.send()

接着就举着电话干等,直到对面传来 xhr.onload 的回应。

听起来还行是吧?但要是你一口气要办五件事,回调地狱能直接给你安排得"明明白白"(看清楚了,是加引号的)。

🔹 原生 XHR 写法长这样,感受一下吧:
const xhr = new XMLHttpRequest();

xhr.open('GET', '/api/user');

xhr.onload = function() {

if (xhr.status === 200) {

console.log(JSON.parse(xhr.responseText));

}

};

xhr.send();

你可能会问,"这也没有回调地狱呀",那试想一下,你在第一个请求200后,需要再用返回数据进一步请求呢?那这整个套餐是不是就要再来一份?

这里还有一点要特别注意:

XHR 对请求状态的判断特别啰嗦,onload 只处理成功,网络错误你得监听 onerror,超时还得单独设 timeout,漏掉一个线上就能崩给你看。

🛠️ jQuery 时代的"温柔乡"

后来 jQuery 出现了,用 $.ajax() 一个方法把我们从严苛的回调和浏览器兼容地狱里捞了出来。

更绝的是,它搞出了 $.get$.post 这些简写,配合 donefail 的链式语法,简直丝滑。

🔹 jQuery 封装下的请求,就清晰得像点外卖了:
$.ajax({

url: '/api/user',

type: 'GET',

dataType: 'json'

})

.done(function(data) {

console.log(data);

})

.fail(function(jqXHR, textStatus) {

console.log('请求失败:' + textStatus);

});

但是!重点来了:

已经2026了,现在要是你还为发个请求就引入一整个几十 KB 的 jQuery 库,项目打包体积就上去了。

咱们选择工具,我认为顺手的才是最好的,没必要为了用个螺丝刀就搬来整个工具箱,真不值当。

于是,原生 fetch 成了咱的新希望。

🚨 Fetch 很现代,但坑也多到防不胜防

fetch 是 ES6 带来的原生 API,基于 Promise,写起来终于有了现代 JavaScript 的味道。

但很不爽的是,它那个"只拒网络错,不拒 HTTP 错"的臭脾气,让我实实在在地翻过几次车,怎么改都拿不到数据。

🔹 给你演示下它最基本的请求:
fetch('/api/user')

.then(res => res.json())

.then(data => console.log(data))

.catch(err => console.log('出错啦', err));

你以为这样写就 Ok 了?

成功了咱能拿到解析的数据,出错了,有 catch 呢!

不不不,你高估了它的 catch,如果服务器返回 404 或 500,fetch 默认也当作"成功了"!.catch 根本抓不到!

你这时还在兴高采烈地去 res.json(),那解析出来的东西可能完全不是你想的那个了,页面可能直接就报错了。

根据以往的血泪经验,正确的做法还是要先检查 res.ok,不 ok 立刻手动抛出一个错误,不然等线上用户截图过来,你 debug 都找不到北。

🔹 还有两个容易翻车的点:

🔸 fetch 默认不携带 cookie,需要手动设置 credentials: 'include'

🔸 处理超时 也是个麻烦,得配合 AbortController 写一堆模板代码,远不如第三方库方便。

👑 为什么说 Axios 是当下的"最优解"

终于说到我的心头好了。Axios 本质上也是对 XHR 的封装 ,但它把我们在 fetch 上踩过的坑,全用贴心的默认配置填平了。

🔹 看这段 Axios 代码,舒坦吗?
axios.get('/api/user')

.then(res => console.log(res.data))

.catch(err => {

if (err.response) {

// 服务器返回了状态码,且超出 2xx

console.log('状态错误:' + err.response.status);

} else if (err.request) {

// 请求发出去了,但没收到响应

console.log('网络超时或无响应');

}

});

它直接帮你把"非 2xx 状态码 "判为 reject,省去了手写检查。

返回数据也已经自动包装在 res.data 里了,它还内置了超时配置请求拦截器响应拦截器,全局处理 loading 和 token 刷新简直不要太优雅。

再啰嗦一句

我在几乎所有项目里都会直接用 Axios 实例封装一个 request.js,把 baseURL、超时时间、统一错误弹窗全配进去,整个项目的 HTTP 层一下就干净了,谁都别想偷偷写"裸请求"。

📊 一张表说清怎么选

🔹 XHR

除非你在维护 IE 老古董,否则别主动用。

🔹 jQuery Ajax

旧项目有在用就接着用,新项目别为了它引入 jQuery。

🔹 Fetch

适合写点 Demo、Service Worker 或对包体积要求极致的小工具,但记得,一定要手写中间件逻辑处理好错误和超时

🔹 Axios

团队协作、中大型项目、需要请求/响应拦截的场景,闭眼选它。

代码量少,坑基本被填平,心情愉悦。

但说到底,选哪个都不是绝对的真理,还是要看你的项目上下文。

但作为摸爬滚打多年的程序媛,我太清楚"少写一行就是赚到,少踩一坑就是大福 "的真理了。

如果你不想把时间耗在跟 fetch 的各种小脾气作斗争上,Axios 就是那个帮你搬开石头的贴心老友。


是不是已经开始回忆自己项目里的请求代码了?

觉得这期干货对你有用的,点个赞告诉我 ,要是怕后面找不到,火速收藏 起来,还没关注的铁子赶紧点一下关注,后面我会持续拆解更多实战里的"暗坑"和"捷径",咱们下篇文章,不见不散啦!🎯