axios 是如何封装 HTTP 请求的

Axios 毋庸多说大家在前端开发中常用的一个发送 HTTP 请求的库,用过的都知道。本文用来整理项目中常用的 Axios 的封装使用。同时学习源码,手写实现 Axios 的核心代码。


Axios 常用封装
是什么
Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。它的特性:
从浏览器中创建 XMLHttpRequests 从 node.js 创建 http 请求 支持 Promise API 拦截请求和响应 转换请求数据和响应数据 取消请求 自动转换 JSON 数据 客户端支持防御 XSRF 官网地址:http://www.axios-js.com/zh-cn/docs/#axios-config
Axios 使用方式有两种:一种是直接使用全局的 Axios 对象;另外一种是通过 axios.create(config) 方法创建一个实例对象,使用该对象。两种方式的区别是通过第二种方式创建的实例对象更清爽一些;全局的 Axios 对象其实也是创建的实例对象导出的,它本身上加载了很多默认属性。后面源码学习的时候会再详细说明。
请求
Axios 这个 HTTP 的库比较灵活,给用户多种发送请求的方式,以至于有些混乱。细心整理会发现,全局的 Axios(或者 axios.create(config)创建的对象) 既可以当作对象使用,也可以当作函数使用:
//?axios?当作对象使用
axios.request(config)
axios.get(url[,?config])
axios.post(url[,?data[,?config]])
// axios()?当作函数使用。?发送 POST 请求
axios({
??method:?'post',
??url:?'/user/12345',
??data:?{
????firstName:?'Fred',
????lastName:?'Flintstone'
??}
});
后面源码学习的时候会再详细说明为什么 Axios 可以实现两种方式的使用。
取消请求
可以使用 CancelToken.source 工厂方法创建 cancel token:
const?CancelToken?=?axios.CancelToken;
const?source?=?CancelToken.source();
axios.get('/user/12345',?{
??cancelToken:?source.token
}).catch(function(thrown)?{
??if?(axios.isCancel(thrown))?{
????console.log('Request?canceled',?thrown.message);
??}?else?{
?????//?处理错误
??}
});
//?取消请求(message?参数是可选的)
source.cancel('Operation?canceled?by?the?user.');
source 有两个属性:一个是 source.token 标识请求;另一个是 source.cancel() 方法,该方法调用后,可以让 CancelToken 实例的 promise 状态变为 resolved,从而触发 xhr 对象的 abort() 方法,取消请求。
拦截
Axios 还有一个奇妙的功能点,可以在发送请求前对请求进行拦截,对相应结果进行拦截。结合业务场景的话,在中台系统中完成登录后,获取到后端返回的 token,可以将 token 添加到 header 中,以后所有的请求自然都会加上这个自定义 header。
//拦截1?请求拦截
instance.interceptors.request.use(function(config){
????//在发送请求之前做些什么
????const?token?=?sessionStorage.getItem('token');
????if(token){
????????const?newConfig?=?{
????????????...config,
????????????headers:?{
????????????????token:?token
????????????}
????????}
????????return?newConfig;
????}else{
????????return?config;
????}
},?function(error){
????//对请求错误做些什么
????return?Promise.reject(error);
});
我们还可以利用请求拦截功能实现 取消重复请求,也就是在前一个请求还没有返回之前,用户重新发送了请求,需要先取消前一次请求,再发送新的请求。比如搜索框自动查询,当用户修改了内容重新发送请求的时候需要取消前一次请求,避免请求和响应混乱。再比如表单提交按钮,用户多次点击提交按钮,那么我们就需要取消掉之前的请求,保证只有一次请求的发送和响应。
实现原理是使用一个对象记录已经发出去的请求,在请求拦截函数中先判断这个对象中是否记录了本次请求信息,如果已经存在,则取消之前的请求,将本次请求添加进去对象中;如果没有记录过本次请求,则将本次请求信息添加进对象中。最后请求完成后,在响应拦截函数中执行删除本次请求信息的逻辑。
//?拦截2???重复请求,取消前一个请求
const?promiseArr?=?{};
instance.interceptors.request.use(function(config){
????console.log(Object.keys(promiseArr).length)
????//在发送请求之前做些什么
????let?source=null;
????if(config.cancelToken){
????????//?config?配置中带了?source?信息
????????source?=?config.source;
????}else{
????????const?CancelToken?=?axios.CancelToken;
????????source?=?CancelToken.source();
????????config.cancelToken?=?source.token;
????}
????const?currentKey?=?getRequestSymbol(config);
????if(promiseArr[currentKey]){
????????const?tmp?=?promiseArr[currentKey];
????????tmp.cancel("取消前一个请求");
????????delete?promiseArr[currentKey];
????????promiseArr[currentKey]?=?source;
????}else{
????????promiseArr[currentKey]?=?source;
????}
????return?config;
},?function(error){
????//对请求错误做些什么
????return?Promise.reject(error);
});
//?根据?url、method、params?生成唯一标识,大家可以自定义自己的生成规则
function?getRequestSymbol(config){
????const?arr?=?[];
????if(config.params){
????????const?data?=?config.params;
????????for(let?key?of?Object.keys(data)){
????????????arr.push(key+"&"+data[key]);
????????}
????????arr.sort();
????}
????return?config.url+config.method+arr.join("");
}
instance.interceptors.response.use(function(response){
????const?currentKey?=?getRequestSymbol(response.config);
????delete?promiseArr[currentKey];
????return?response;
},?function(error){
????//对请求错误做些什么
????return?Promise.reject(error);
});
最后,我们可以在响应拦截函数中统一处理返回码的逻辑:
//?响应拦截
instance.interceptors.response.use(function(response){
????//?401?没有登录跳转到登录页面
????if(response.data.code===401){
????????window.location.href?=?"http://127.0.0.1:8080/#/login";
????}else?if(response.data.code===403){
????????//?403?无权限跳转到无权限页面
????????window.location.href?=?"http://127.0.0.1:8080/#/noAuth";
????}
????return?response;
},?function(error){
????//对请求错误做些什么
????return?Promise.reject(error);
})
文件下载
通常文件下载有两种方式:一种是通过文件在服务器上的对外地址直接下载;还有一种是通过接口将文件以二进制流的形式下载。
第一种:同域名 下使用 a 标签下载:
//?httpServer.js
const?express?=?require("express");
const?path?=?require('path');
const?app?=?express();
//静态文件地址
app.use(express.static(path.join(__dirname,?'public')))
app.use(express.static(path.join(__dirname,?'../')));
app.listen(8081,?()?=>?{
??console.log("服务器启动成功!")
});
//?index.html
<a?href="test.txt"?download="test.txt">下载</a>

这时候,我们可以将请求文件下载的逻辑进行封装。将二进制文件流存在 Blob 对象中,再将其转为 url 对象,最后通过 a 标签下载。
//封装下载
export?function?downLoadFetch(url,?params?=?{},?config={})?{
????//取消
????const?downSource?=?axios.CancelToken.source();
????document.getElementById('downAnimate').style.display?=?'block';
????document.getElementById('cancelBtn').addEventListener('click',?function(){
????????downSource.cancel("用户取消下载");
????????document.getElementById('downAnimate').style.display?=?'none';
????},?false);
????//参数
????config.params?=?params;
????//超时时间
????config.timeout?=?config.timeout???config.timeout?:?defaultDownConfig.timeout;
????//类型
????config.responseType?=?defaultDownConfig.responseType;
????//取消下载
????config.cancelToken?=?downSource.token;
????return?instance.get(url,?config).then(response=>{
????????const?content?=?response.data;
????????const?url?=?window.URL.createObjectURL(new?Blob([content]));
????????//创建?a?标签
????????const?link?=?document.createElement('a');
????????link.style.display?=?'none';
????????link.href?=?url;
????????//文件名??Content-Disposition:?attachment;?filename=download.txt
????????const?filename?=?response.headers['content-disposition'].split(";")[1].split("=")[1];
????????link.download?=?filename;
????????document.body.appendChild(link);
????????link.click();
????????document.body.removeChild(link);
????????return?{
????????????status:?200,
????????????success:?true
????????}
????})
}

https://juejin.cn/post/6878912072780873742

手写 Axios 核心代码
写了这么多用法终于到正题了,手写 Axios 核心代码。Axios 这个库源码不难阅读,没有特别复杂的逻辑,大家可以放心阅读 关注公众号:拾黑(shiheibook)了解更多 [广告]赞助链接:
四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/
关注网络尖刀微信公众号随时掌握互联网精彩
- 1 习近平将发表二〇二六年新年贺词 7904141
- 2 2026年国补政策来了 7808738
- 3 东部战区:开火!开火!全部命中! 7712893
- 4 2026年这些民生政策将惠及百姓 7616985
- 5 小学食堂米线过期2.5小时被罚5万 7519709
- 6 解放军喊话驱离台军 原声曝光 7428214
- 7 为博流量直播踩烈士陵墓?绝不姑息 7327605
- 8 每月最高800元!多地发放养老消费券 7238391
- 9 数字人民币升级 1月1日起将计付利息 7141831
- 10 2026年1月1日起 一批新规将施行 7040675








CSDN
