当前位置: 首页 > news >正文

React 中基于 Axios 的二次封装(含请求守卫)

React 中基于 Axios 的二次封装(含请求守卫)

下面是一个完整的 Axios 二次封装方案,包含 GET、POST 等方法的封装,并加入了请求守卫(拦截器)功能。

1. 基础封装 (axiosInstance.js)

importaxiosfrom'axios';import{message}from'antd';// 使用 Ant Design 的 message 作为示例,可替换为其他 UI 库或自定义// 创建 axios 实例constaxiosInstance=axios.create({baseURL:process.env.REACT_APP_API_BASE_URL||'/api',// 基础路径timeout:10000,// 请求超时时间withCredentials:true,// 跨域请求时是否需要使用凭证});// 请求拦截器axiosInstance.interceptors.request.use((config)=>{// 在发送请求之前做些什么// 例如:添加 tokenconsttoken=localStorage.getItem('token');if(token){config.headers.Authorization=`Bearer${token}`;}// 可以在这里添加全局请求参数或修改 config// config.params = { ...config.params, lang: 'zh-CN' };returnconfig;},(error)=>{// 对请求错误做些什么console.error('请求拦截器错误:',error);returnPromise.reject(error);});// 响应拦截器axiosInstance.interceptors.response.use((response)=>{// 对响应数据做点什么// 假设后端返回的数据结构为 { code: 200, data: {}, message: '' }constres=response.data;if(res.code===200){returnres.data;// 直接返回数据部分}else{// 处理业务错误message.error(res.message||'请求错误');returnPromise.reject(newError(res.message||'Error'));}},(error)=>{// 对响应错误做点什么console.error('响应拦截器错误:',error);if(error.response){// 根据 HTTP 状态码处理不同错误switch(error.response.status){case401:message.error('未授权,请登录');// 这里可以跳转到登录页// window.location.href = '/login';break;case403:message.error('拒绝访问');break;case404:message.error('请求的资源不存在');break;case500:message.error('服务器错误');break;default:message.error(error.response.data.message||'请求失败');}}elseif(error.message.includes('timeout')){message.error('请求超时');}else{message.error('网络错误');}returnPromise.reject(error);});exportdefaultaxiosInstance;

2. 请求方法封装 (request.js)

importaxiosInstancefrom'./axiosInstance';/** * 封装 GET 请求 * @param {string} url 请求地址 * @param {object} params 请求参数 * @param {object} config 额外配置 * @returns Promise */exportfunctionget(url,params={},config={}){returnaxiosInstance.get(url,{params,...config});}/** * 封装 POST 请求 * @param {string} url 请求地址 * @param {object} data 请求体数据 * @param {object} config 额外配置 * @returns Promise */exportfunctionpost(url,data={},config={}){returnaxiosInstance.post(url,data,config);}/** * 封装 PUT 请求 * @param {string} url 请求地址 * @param {object} data 请求体数据 * @param {object} config 额外配置 * @returns Promise */exportfunctionput(url,data={},config={}){returnaxiosInstance.put(url,data,config);}/** * 封装 DELETE 请求 * @param {string} url 请求地址 * @param {object} params 请求参数 * @param {object} config 额外配置 * @returns Promise */exportfunctiondel(url,params={},config={}){returnaxiosInstance.delete(url,{params,...config});}/** * 封装上传请求 * @param {string} url 请求地址 * @param {FormData} formData 表单数据 * @param {object} config 额外配置 * @returns Promise */exportfunctionupload(url,formData,config={}){returnaxiosInstance.post(url,formData,{headers:{'Content-Type':'multipart/form-data',},...config,});}// 可以继续添加其他封装方法...

3. 使用示例

importReact,{useEffect,useState}from'react';import{get,post}from'./request';functionUserList(){const[users,setUsers]=useState([]);const[loading,setLoading]=useState(false);const[error,setError]=useState(null);useEffect(()=>{constfetchUsers=async()=>{setLoading(true);try{constdata=awaitget('/users');setUsers(data);}catch(err){setError(err.message);}finally{setLoading(false);}};fetchUsers();},[]);consthandleAddUser=async()=>{try{constnewUser={name:'New User',age:25};constdata=awaitpost('/users',newUser);console.log('添加成功:',data);// 可以刷新列表或做其他操作}catch(err){console.error('添加失败:',err);}};if(loading)return<div>加载中...</div>;if(error)return<div>错误:{error}</div>;return(<div><button onClick={handleAddUser}>添加用户</button><ul>{users.map(user=>(<li key={user.id}>{user.name}</li>))}</ul></div>);}exportdefaultUserList;

4. 高级功能扩展

4.1 请求取消功能

// 在 axiosInstance.js 中添加constCancelToken=axios.CancelToken;constsourceMap=newMap();// 用于存储请求的取消函数// 修改请求拦截器axiosInstance.interceptors.request.use((config)=>{// 如果已有相同请求在执行,则取消之前的请求constrequestKey=`${config.method}-${config.url}`;if(sourceMap.has(requestKey)){constcancel=sourceMap.get(requestKey);cancel('取消重复请求');}// 创建新的取消令牌constsource=CancelToken.source();config.cancelToken=source.token;sourceMap.set(requestKey,source.cancel);returnconfig;},(error)=>{returnPromise.reject(error);});// 修改响应拦截器axiosInstance.interceptors.response.use((response)=>{// 请求成功后从 map 中移除对应的取消函数constconfig=response.config;constrequestKey=`${config.method}-${config.url}`;sourceMap.delete(requestKey);returnresponse;},(error)=>{if(axios.isCancel(error)){console.log('请求已取消:',error.message);}// 其他错误处理...returnPromise.reject(error);});// 导出取消请求的方法exportfunctioncancelRequest(method,url){constrequestKey=`${method}-${url}`;if(sourceMap.has(requestKey)){constcancel=sourceMap.get(requestKey);cancel('主动取消请求');sourceMap.delete(requestKey);}}

4.2 请求重试机制

// 在 axiosInstance.js 中添加constretryCount=2;// 重试次数constretryDelay=1000;// 重试延迟时间(ms)// 修改请求拦截器或单独封装一个重试函数asyncfunctionretryRequest(config,retryNum=retryCount){try{constresponse=awaitaxiosInstance(config);returnresponse;}catch(error){if(retryNum<=0){throwerror;}console.log(`请求失败,重试${retryNum}次...`);awaitnewPromise(resolve=>setTimeout(resolve,retryDelay));returnretryRequest(config,retryNum-1);}}// 然后在需要的地方使用 retryRequest 代替直接调用 axiosInstance

5. TypeScript 版本

如果需要 TypeScript 版本,可以这样修改:

// axiosInstance.tsimportaxios,{AxiosInstance,AxiosRequestConfig,AxiosResponse,AxiosError}from'axios';interfaceResponseData<T=any>{code:number;data:T;message:string;}constaxiosInstance:AxiosInstance=axios.create({baseURL:process.env.REACT_APP_API_BASE_URL||'/api',timeout:10000,withCredentials:true,});axiosInstance.interceptors.request.use((config:AxiosRequestConfig)=>{consttoken=localStorage.getItem('token');if(token){config.headers!.Authorization=`Bearer${token}`;}returnconfig;},(error:AxiosError)=>{returnPromise.reject(error);});axiosInstance.interceptors.response.use((response:AxiosResponse<ResponseData>)=>{constres=response.data;if(res.code===200){returnres.data;}else{returnPromise.reject(newError(res.message||'Error'));}},(error:AxiosError)=>{// 错误处理...returnPromise.reject(error);});exportdefaultaxiosInstance;// request.tsimportaxiosInstancefrom'./axiosInstance';exportfunctionget<T=any>(url:string,params?:any,config?:AxiosRequestConfig):Promise<T>{returnaxiosInstance.get(url,{params,...config});}exportfunctionpost<T=any>(url:string,data?:any,config?:AxiosRequestConfig):Promise<T>{returnaxiosInstance.post(url,data,config);}// 其他方法...

这个封装方案提供了:

  1. 基础请求方法的封装
  2. 请求和响应拦截器(守卫)
  3. 错误统一处理
  4. 可扩展的高级功能(请求取消、重试等)
  5. TypeScript 支持(可选)

你可以根据实际项目需求进行调整和扩展。

http://www.jsqmd.com/news/572720/

相关文章:

  • P8340 [AHOI2022] 山河重整
  • 效率飞跃:用快马ai定制openclaw多场景开发环境模板
  • Web前端安全核心知识总结
  • 别再傻傻分不清!Android Studio里androidTest和test文件夹到底怎么用?(附实战代码对比)
  • 解锁高效链接的专业领域
  • 微信立减金回收(方法、流程、折扣) - 京顺回收
  • 忍者像素绘卷效果展示:高对比度线条+32色调色板生成的复古游戏风插画
  • EasyHTTP:ESP32轻量级HTTP客户端库设计与实践
  • PostGIS数据库配置与gdb数据高效导入实战
  • 3个强力步骤!开源工具G-Helper实现华硕笔记本电池续航优化解决方案
  • 2026年 五轴车铣复合加工中心厂家实力推荐榜:高精度、高效率、高稳定性的智能智造解决方案首选 - 品牌企业推荐师(官方)
  • 同样是加热,为什么夹爪热传导更适合空心杯电机?
  • 2026年口碑营销GEO优化服务商真实测评:艾奇GEO等三家选型指南 - 小白条111
  • 新手零门槛学数据库:在快马平台完成你的第一个SQL查询
  • 蛋白共表达技术详解:从多基因构建到蛋白复合体研究的核心工具
  • D3KeyHelper智能辅助工具:暗黑3效率提升全流程攻略
  • 20260326网安学习日志—文件上传漏洞
  • Phi-4-mini-reasoning Chainlit定制化教程:添加LaTeX渲染与公式高亮
  • 如何用MelonLoader打造Unity游戏定制体验:双引擎支持的模组加载方案
  • 实测Qwen3-Reranker-0.6B:轻量级模型如何重塑企业RAG系统?
  • SEO 整站优化和内容营销有什么联系
  • 牛客 区间翻转
  • AI助力内容创作:Asian Beauty Z-Image Turbo生成社交媒体配图实战
  • FTDI飞特帝亚 FT232RQ-REEL QFN32 USB转换芯片
  • 3个高效方案实现IDM免费使用:开源工具永久激活全指南
  • 袁永福 电子病历,医疗信息化
  • 探索AI编程新范式:在快马平台像使用卓晴一样与多模型AI结对编程
  • 用ESP32-S3和Minimax API,手把手教你做个会聊天的AI语音助手(附完整代码)
  • ROS2开发环境搭建踩坑实录:Win11 + WSL + Ubuntu 22.04 LTS 避坑指南
  • WindowResizer终极教程:三分钟掌握Windows窗口自由调整技巧