
这篇文章就帮你把这些问题彻底理清楚。我们先从AJAX的原理讲起,不用复杂术语,而是用“浏览器和服务器的对话”类比,把“异步请求”的底层逻辑、核心步骤拆解得明明白白,让你真正理解AJAX不是“黑盒工具”,而是前端和后端通信的“底层规则”;接着用真实代码实例对比axios和fetch——从最基础的“发送GET请求”写法,到“拦截器”“自动转换JSON”“错误处理”这些关键功能差异,再到兼容性、体积大小等细节,全用具体场景帮你捋清楚;最后结合实际开发场景给出明确 如果需要复杂拦截、统一处理请求,选axios更高效;如果追求轻量、原生兼容,fetch更适合。
不管你是刚入门的新手想打牢基础,还是工作中常写请求的老鸟想梳理知识,看完这篇,AJAX原理和请求工具的选择问题,就能一次性搞懂。
你做前端开发时,有没有过这种崩溃时刻?写了个请求代码,要么页面卡着不动,要么拿到的数据是“乱码”,要么明明接口返回404,控制台却没报错——其实这些问题,大多和AJAX原理没搞懂,或者选了不适合的请求工具(axios/fetch)有关。今天我用自己踩过的坑、帮朋友解决过的问题,把这些知识点掰碎了讲,看完你再写请求代码,肯定比之前顺10倍。
浏览器和服务器的“悄悄话”:AJAX到底怎么工作?
很多人对AJAX的印象是“异步请求”,但其实它的本质是浏览器和服务器之间的“秘密对话”——不用刷新页面,就能偷偷传数据。我举个最接地气的例子:你去奶茶店点单,以前得站在柜台前等奶茶做好(同步),现在可以扫个码下单,然后找位置坐会儿(异步),奶茶做好了店员会喊你(响应)——AJAX就是这个“扫码下单+喊你取餐”的过程。
具体来说,AJAX的核心是XMLHttpRequest(XHR)——你可以把它当成一个“通讯员”,专门帮你和服务器传消息。它的工作流程就四步,我用“帮朋友查快递”的场景给你模拟一遍:
var xhr = new XMLHttpRequest()
——相当于你找了个跑腿的,专门帮你查快递。 xhr.open('GET', 'https://api.kuaidi100.com/query?id=12345')
——你跟跑腿的说:“去查一下单号12345的快递,用GET方式问(就是‘获取信息’)。” xhr.send()
——跑腿的去快递站了。 xhr.onreadystatechange = function() { if(xhr.readyState === 4 && xhr.status === 200) { console.log(xhr.responseText) } }
——跑腿的回来告诉你:“快递到小区门口了(readyState=4表示完成,status=200表示成功)”,你就能拿到快递信息(xhr.responseText)。是不是特好懂?我之前帮朋友做一个美食博客的“最新评论”功能,刚开始直接用同步请求,用户点“加载更多”时,页面卡着不动,像死机了一样——因为同步请求会“霸占”浏览器,直到服务器返回数据才能做别的。后来换成AJAX异步请求,用户点完按钮还能继续划页面,评论加载好了自动弹出来,体验瞬间好太多。
但 AJAX 也不是完美的——它有个“同源策略”的限制,就是通讯员只能去和当前页面域名、端口、协议都一样的服务器传消息。比如你本地页面是http://localhost:3000
,想调用https://api.taobao.com
的接口,通讯员会直接拒绝(跨域错误)。这时候得让后端帮忙“开绿灯”(设置CORS,也就是Access-Control-Allow-Origin: *
),或者用JSONP(但现在基本不用了)。我去年做一个电商项目时,就因为后端没开CORS,折腾了一下午才解决——所以记着,跨域问题不是前端的锅,得找后端同学帮忙。
选axios还是fetch?用3个真实场景帮你做决定
现在前端请求工具就俩主流:axios(第三方库)和fetch(浏览器原生API)。我见过太多人纠结“选哪个”,其实根本不用死记硬背,用3个开发中最常遇到的场景,你自己就能做决定。
场景1:发送简单GET请求——写法差在哪里?
假设你要获取“今日天气”的数据,接口是https://api.weather.com/v1/current?city=beijing
。
用axios的写法:
axios.get('https://api.weather.com/v1/current?city=beijing')
.then(res => {
console.log('天气数据:', res.data) // 直接拿到JSON数据
})
.catch(err => {
console.log('请求失败:', err)
})
用fetch的写法:
fetch('https://api.weather.com/v1/current?city=beijing')
.then(res => {
if(!res.ok) { // 必须手动检查HTTP状态
throw new Error('请求失败:' + res.status)
}
return res.json() // 必须手动转换JSON
})
.then(data => {
console.log('天气数据:', data)
})
.catch(err => {
console.log('错误:', err)
})
看出区别了吗?axios的链式调用更“省心”——不用手动检查状态,不用手动转JSON,直接拿res.data
就行。而fetch得“多走两步”:先检查res.ok
(不然404不会报错),再调用res.json()
才能拿到数据。我之前帮同事看代码,他用fetch的时候忘了加res.json()
,结果控制台打印出ReadableStream
(可读流),折腾了半小时才反应过来——这就是没搞懂fetch的“脾气”。
场景2:处理JSON数据——谁更省心?
做登录功能时,你需要给后端传{ username: 'admin', password: '123456' }
这样的JSON数据。
用axios的写法:
axios.post('https://api.example.com/login', {
username: 'admin',
password: '123456'
})
.then(res => {
console.log('登录结果:', res.data)
})
用fetch的写法:
fetch('https://api.example.com/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json' // 必须手动设置
},
body: JSON.stringify({ // 必须手动转成字符串
username: 'admin',
password: '123456'
})
})
.then(res => res.json())
.then(data => {
console.log('登录结果:', data)
})
axios有多贴心?它会自动帮你做3件事:
JSON.stringify
); Content-Type: application/json
; res.json()
)。 而fetch得你“亲手”做这3件事——我之前做登录功能时,用fetch忘了设置Content-Type
,结果后端告诉我“没收到数据”,查了半天才发现是这个问题。后来换成axios,直接传对象就行,省了好多事儿。
场景3:错误处理——踩过的坑告诉你答案
假设你请求一个不存在的接口(比如https://api.example.com/nonexistent
),会发生什么?
axios的表现:
直接进入catch
,错误信息里会明确写着Request failed with status code 404
——你一眼就知道是“接口不存在”。
fetch的表现:
不会进入catch
!因为fetch的“错误定义”很严格:只有网络错误(比如断网、服务器宕机)才会reject,HTTP错误(比如404、500)不算“错误”。你得手动检查res.ok
(res.ok
是true
表示状态码200-299,否则是false
),然后自己抛出错误:
fetch('https://api.example.com/nonexistent')
.then(res => {
if(!res.ok) {
throw new Error(请求失败:${res.status}
) // 手动抛错
}
return res.json()
})
.catch(err => {
console.log(err) // 现在才会打印“请求失败:404”
})
我去年在做一个电商项目时,就踩过fetch的坑:用户点“提交订单”按钮,接口返回404,但页面没任何提示(因为没进入catch),用户以为没提交成功,反复点了好几次——后来换成axios,直接在catch里弹出“提交失败,请重试”,问题就解决了。
一张表帮你快速对比核心差异
为了让你更清楚,我把axios和fetch的核心差异做成了表格——直接看这张表,就能决定选哪个:
核心维度 | axios | fetch |
---|---|---|
请求方法支持 | 支持所有常用方法(GET/POST等),写法简洁 | 支持所有方法,但需手动配置 |
自动转换JSON | 是(请求/响应都自动处理) | 否(需手动调用JSON.stringify/res.json()) |
错误处理 | HTTP错误(404/500)会reject | 仅网络错误会reject,HTTP错误需手动检查 |
兼容性 | 支持IE11及以上(需引入库) | 支持Chrome 42+/Firefox 39+,IE11需polyfill |
体积大小 | 约10KB(min版) | 原生API,无需额外引入 |
看到这儿,你应该有答案了吧?如果你的项目需要:
选axios准没错。如果你的项目追求:
fetch是更好的选择。
其实我身边的前端同事,80%的项目都在用axios——不是说fetch不好,而是axios把开发中常遇到的“麻烦事”都帮你解决了,能省很多时间。比如拦截器功能(axios可以统一处理所有请求的token,不用每个请求都写一遍)、取消请求(比如用户快速点击按钮,可以取消之前的请求),这些都是fetch没有的“加分项”。
你最近做项目用了axios还是fetch?有没有遇到什么奇怪的问题?欢迎评论区聊两句,我帮你参谋参谋—— 前端的坑,踩过才知道有多疼啊~
本文常见问题(FAQ)
AJAX名字里有XML,是不是一定要用XML传数据?
其实不是哦,AJAX里的XML是“历史遗留”——早期AJAX主要用XML格式传数据,所以名字里带了XML。但现在前端开发几乎都用JSON传数据,AJAX的核心是“异步请求+不刷新页面”,跟用什么格式没关系。比如你现在用axios发请求,传的是JSON对象,本质还是AJAX的范畴。
axios和fetch的错误处理到底不一样在哪?我总搞混
最核心的区别是“HTTP错误算不算错”——比如请求一个不存在的接口(404),axios会直接进catch,告诉你“Request failed with status code 404”;但fetch不会,它觉得“我成功发了请求,只是服务器返回404”,所以得你手动检查res.ok(res.ok是true才表示200-299的成功状态),再自己抛错才能进catch。我之前用fetch的时候没检查res.ok,结果404了页面还没反应,查了半天才找到问题。
项目要兼容IE11,选axios还是fetch啊?
优先选axios!因为axios本身支持IE11,不用额外加代码;但fetch是现代浏览器的原生API,IE11不支持,得加polyfill(比如whatwg-fetch)才能用。如果你的项目要覆盖IE11用户,用axios会省很多兼容性的麻烦——我之前帮客户做官网,一开始用fetch,结果IE11下全报错,后来换成axios就好了。
用fetch拿到ReadableStream是怎么回事?怎么解决?
这是因为你没手动转JSON!fetch的响应结果默认是一个ReadableStream(可读流),得调用res.json()才能把它转换成JSON对象。比如你请求天气接口,用fetch的话,得先写.then(res => res.json()),再在后面的.then里处理数据。我同事之前写fetch代码忘了这一步,结果控制台打印出ReadableStream,还以为接口返回错了,折腾了半小时才搞明白——记住,fetch不会自动帮你转JSON,得自己动手。
axios的拦截器有啥用?我怎么没感觉到它的好处?
拦截器能帮你“统一处理所有请求/响应”,比如项目里所有请求都要带token,你不用每个请求都写一遍token,用axios的请求拦截器就能搞定:比如写一段axios.interceptors.request.use(config => { config.headers.Authorization = ‘Bearer ‘ + token; return config; }),这样所有请求都会自动加token。再比如响应拦截器,可以统一处理错误,比如所有401(未登录)的响应都跳转到登录页——这些功能fetch没有,得自己写逻辑,而axios帮你封装好了,能省超多重复代码。我现在做项目,不管大小都用axios的拦截器,真的能少写好多冗余代码。