一、什么是axios,有什么特性
描述
axios是一个基于promise的HTTP库,可以用在浏览器或者node.js中。本文围绕XHR。
axios提供两个http请求适配器,XHR和HTTP。XHR的核心是浏览器端的XMLHttpRequest对象;HTTP的核心是node的http.request方法。
特性:
从浏览器中创建XMLHttpRequests
从node.js创建http请求
支持promise API
拦截请求与响应
转换请求数据与响应数据
取消请求
自动转换JSON数据
客户端支持防御XSRF
背景
自Vue2.0起,尤大宣布取消对vue-resource的官方推荐,转而推荐axios。现在axios已经成为大部分Vue开发者的首选,目前在github上有87.3k star。axios的熟练使用和基本封装也成为了vue技术栈系列必不可少的一部分。如果你还不了解axios,建议先熟悉 axios官网文档。
基本使用
安装
npminstallaxios-S
使用
importaxiosfrom'axios'//为给定ID的user创建请求axios.get('/user?ID=12345').then(function(response){console.log(response);}).catch(function(error){console.log(error);});//上面的请求也可以这样做axios.get('/user',{params:{ID:12345}}).then(function(response){console.log(response);}).catch(function(error){console.log(error);});二、Vue项目中为什么要封装axios
axios的API很友好,可以在项目中直接使用。但是在大型项目中,http请求很多,且需要区分环境, 每个网络请求有相似需要处理的部分,如下,会导致代码冗余,破坏工程的可维护性,扩展性
axios('http://www.kaifa.com/data',{//配置代码method:'GET',timeout:3000,withCredentials:true,headers:{'Content-Type':'application/json'},//其他请求配置...}).then((data)=>{//todo:真正业务逻辑代码console.log(data);},(err)=>{//错误处理代码if(err.response.status===401){//handleauthorizationerror}if(err.response.status===403){//handleserverforbiddenerror}//其他错误处理.....console.log(err);});环境区分
请求头信息
请求类型
请求超时时间
timeout: 3000
允许携带cookie
withCredentials: true
响应结果处理
登录校验失败
无权限
成功
...
三、Vue项目中如何封装axios
axios文件封装在目录src/utils/https.js,对外暴露callApi函数
1、环境区分
callApi函数暴露prefixUrl参数,用来配置api url前缀,默认值为api
//src/utils/https.jsimportaxiosfrom'axios'exportconstcallApi=({url,...prefixUrl='api'})=>{if(!url){consterror=newError('请传入url')returnPromise.reject(error)}constfullUrl=`/${prefixUrl}/${url}`...returnaxios({url:fullUrl,...})}看到这里大家可能会问,为什么不用axios提供的配置参数baseURL,原因是baseURL会给每个接口都加上对应前缀,而项目实际场景中,存在一个前端工程,对应多个服务的场景。需要通过不用的前缀代理到不同的服务,baseURL虽然能实现,但是需要二级前缀,不优雅,且在使用的时候看不到真实的api地址是啥,因为代理前缀跟真实地址混合在一起了
使用baseURL,效果如下
函数设置prefixUrl参数,效果如下
利用环境变量及webpack代理(这里用vuecli3配置)来作判断,用来区分开发、测试环境。生产环境同理配置nginx代理
//vue.config.jsconsttargetApi1=process.env.NODE_ENV==='development'?"http://www.kaifa1.com":"http://www.ceshi1.com"consttargetApi2=process.env.NODE_ENV==='development'?"http://www.kaifa2.com":"http://www.ceshi2.com"module.exports={devServer:{proxy:{'/api1':{target:targetApi1,changeOrigin:true,pathRewrite:{'/api1':""}},'/api2':{target:targetApi2,changeOrigin:true,pathRewrite:{'/api2':""}},}}}2、请求头
常见以下三种
(1)application/json
参数会直接放在请求体中,以JSON格式的发送到后端。这也是axios请求的默认方式。这种类型使用最为广泛。
//src/utils/https.jsimportaxiosfrom'axios'importqsfrom'qs'constcontentTypes={json:'application/json;charset=utf-8',urlencoded:'application/x-www-form-urlencoded;charset=utf-8',multipart:'multipart/form-data',}constdefaultOptions={headers:{Accept:'application/json','Content-Type':contentTypes.json,}}exportconstcallApi=({url,data={},options={},contentType='json',//json||urlencoded||multipartprefixUrl='api'})=>{...constnewOptions={...defaultOptions,...options,headers:{'Content-Type':options.headers&&options.headers['Content-Type']||contentTypes[contentType],},}const{method}=newOptionsif(method!=='get'&&method!=='head'){if(datainstanceofFormData){newOptions.data=datanewOptions.headers={'x-requested-with':'XMLHttpRequest','cache-control':'no-cache',}}elseif(options.headers['Content-Type']===contentTypes.urlencoded){newOptions.data=qs.stringify(data)}else{Object.keys(data).forEach((item)=>{if(data[item]===null||data[item]===undefined||data[item]===''){deletedata[item]}})//没有必要,因为axios会将JavaScript对象序列化为JSON//newOptions.data=JSON.stringify(data);}}returnaxios({url:fullUrl,...newOptions,})}注意,在application/json格式下,JSON.stringify处理传参没有意义,因为axios会将JavaScript对象序列化为JSON,也就说无论你转不转化都是JSON
3、请求类型
请求类型参数为axios的options的method字段,传入对应的请求类型如post、get等即可
不封装,使用原生axios时,发送带参数的get请求如下:
//src/service/index.jsimport{callApi}from'@/utils/https';exportconstdelFile=(params)=>callApi({url:`file/delete?systemName=${params.systemName}&menuId=${params.menuId}&appSign=${params.appSign}`,option:{method:'get',},});//或者exportconstdelFile=(params)=>callApi({url:'file/delete',option:{method:'get',params},});官方文档如下
callApi函数暴露method参数,用来配置请求类型,默认值为get
当请求类型为get时,将callApi函数暴露的data参数,设置为options.params,从而参数自动拼接到url地址之后
//src/utils/https.jsimportaxiosfrom'axios'exportconstcallApi=({url,data={},method='get',options={},...prefixUrl='api'})=>{...constnewOptions={...,...options,method}...if(method==='get'){newOptions.params=data}...returnaxios({url:fullUrl,...newOptions,})}4、请求超时时间
//src/utils/https.jsconstdefaultOptions={timeout:15000,}5、允许携带cookie
//src/utils/https.jsconstdefaultOptions={withCredentials:true,}6、响应结果处理
通过.then、.catch()处理
这块需要跟服务端约定接口响应全局码,从而统一处理登录校验失败,无权限,成功等结果
比如有些服务端对于登录校验失败,无权限,成功等返回的响应码都是200,在响应体内返回的状态码分别是20001,20002,10000,在then()中处理
比如有些服务端对于登录校验失败,无权限,成功响应码返回401,403,200,在catch()中处理
importaxiosfrom'axios'//为给定ID的user创建请求axios.get('/user?ID=12345').then(function(response){console.log(response);}).catch(function(error){console.log(error);});//上面的请求也可以这样做axios.get('/user',{params:{ID:12345}}).then(function(response){console.log(response);}).catch(function(error){console.log(error);});0上述方案在Message.error(xx)时,当多个接口返回的错误信息一致时,会存在重复提示的问题,如下图
优化方案,利用防抖,实现错误提示一次,更优雅
四、完整封装及具体使用
代码可访问本人的github
axios-ajax完整封装
importaxiosfrom'axios'//为给定ID的user创建请求axios.get('/user?ID=12345').then(function(response){console.log(response);}).catch(function(error){console.log(error);});//上面的请求也可以这样做axios.get('/user',{params:{ID:12345}}).then(function(response){console.log(response);}).catch(function(error){console.log(error);});1importaxiosfrom'axios'//为给定ID的user创建请求axios.get('/user?ID=12345').then(function(response){console.log(response);}).catch(function(error){console.log(error);});//上面的请求也可以这样做axios.get('/user',{params:{ID:12345}}).then(function(response){console.log(response);}).catch(function(error){console.log(error);});2具体使用
api管理文件在目录src/service下,index.js文件暴露其他模块,其他文件按功能模块划分文件
get请求带参数 自定义前缀代理不同服务 文件类型处理
五、总结
axios封装没有一个绝对的标准,且需要结合项目中实际场景来设计,但是毋庸置疑,axios-ajax的封装是非常有必要的。
原文地址:https://github.com/zxyue25/axios-ajax
其他文章:vue多工程间公共模块处理最佳实践
本文收录专栏【业务总结】旨在沉淀工作中遇到的问题,总结为最佳实践,欢迎关注✨