首次入坑
你是否写过像我这样的代码?
<template>
<div id="app">
<button @click="getData">加载数据</button>
<button @click="getData2">加载数据2</button>
<button @click="getData3">加载数据3</button>
</div>
</template>
<script>
import axios from 'axios'
export default {
methods:{
getData(){
axios.get('http://api.mozlee.com/getdata').then({data}=>{
//todo bala bala~
})
},
getData2(){
axios.get('http://api.mozlee.com/getdata2').then({data}=>{
//todo bala bala~
})
},
getData3(){
axios.get('http://api.mozlee.com/getdata3').then({data}=>{
//todo bala bala~
})
}
}
}
</script>
这个时候服务端小伙伴老王来了,告知你api.mozlee.com这个域即将下线,由api.jackma.com替换,并且将http协议全部更新到https协议。你怎么办?是不是只能一个一个去改axios请求的url?而且在修改的过程中十分繁琐,并且容易出现错改,漏改。机智的小伙伴已经想到用axios的baseURL去解决这个问题。所以我们改写一下这个组件。
改造一,使用baseURL
代码改写如下,这样解决上边老王提出来的问题。
<template>
<div id="app">
<button @click="getData">加载数据</button>
<button @click="getData2">加载数据2</button>
<button @click="getData3">加载数据3</button>
</div>
</template>
<script>
import axios from 'axios'
axios.baseURL = 'https://api.jackma.com'
export default {
methods:{
getData(){
axios.get('/getdata').then({data}=>{
//todo bala bala~
})
},
getData2(){
axios.get('/getdata2').then({data}=>{
//todo bala bala~
})
},
getData3(){
axios.get('/getdata3').then({data}=>{
//todo bala bala~
})
}
}
}
</script>
可是老王这个孩子不省心啊,又过来告诉你我们的/getdata3接口,依然要用老的域名 api.mozlee.com,其他的接口保持 api.jackma.com。此时的你是不是想锤死老王?
改造二,使用create创建实例
面对老王的这次改动,我们来使用axios的create方法创建出不同的用于请求的实例。
<template>
<div id="app">
<button @click="getData">加载数据</button>
<button @click="getData2">加载数据2</button>
<button @click="getData3">加载数据3</button>
</div>
</template>
<script>
import axios from 'axios'
const mozleeAPI = axios.create({
baseURL:'https://api.mozlee.com',
... // 其他config
})
const jackmaAPI = axios.create({
baseURL:'https://api.jackma.com',
... // 其他config
})
axios.baseURL = 'https://api.jackma.com'
export default {
methods:{
getData(){
jackmaAPI.get('/getdata').then({data}=>{
//todo bala bala~
})
},
getData2(){
jackmaAPI.get('/getdata2').then({data}=>{
//todo bala bala~
})
},
getData3(){
mozleeAPI.get('/getdata3').then({data}=>{
//todo bala bala~
})
}
}
}
</script>
此时的你总算舒了口气,完成了这个组件开发,去开发其他组件(功能),但是你发现,TMD这两个创建的请求实例在别的组件也要用到。
改造三,抽离axios相关实例。
此时的我们应该将请求相关的接口进行抽离,再向外部暴露。这样在其他组件就可以引入调用。 我们新建一个api.js
api.js的内容为
import axios from 'axios'
export const mozleeAPI = axios.create({
baseURL:'https://api.mozlee.com',
... // 其他config
})
export const jackmaAPI = axios.create({
baseURL:'https://api.jackma.com',
... // 其他config
})
组件A的内容为
<template>
<div id="app">
<button @click="getData">加载数据</button>
<button @click="getData2">加载数据2</button>
<button @click="getData3">加载数据3</button>
</div>
</template>
<script>
import {mozleeAPI,jackmaAPI} from './api.js'
export default {
methods:{
getData(){
jackmaAPI.get('/getdata').then({data}=>{
//todo bala bala~
})
},
getData2(){
jackmaAPI.get('/getdata2').then({data}=>{
//todo bala bala~
})
},
getData3(){
mozleeAPI.get('/getdata3').then({data}=>{
//todo bala bala~
})
}
}
}
</script>
组件B的内容为
<template>
<div id="app">
<button @click="getData">加载数据</button>
</div>
</template>
<script>
import {jackmaAPI} from './api.js'
export default {
methods:{
getData(){
jackmaAPI.get('/getdata').then({data}=>{
//todo bala bala~
})
}
}
}
</script>
到此,可算是解决了多组件复用axios实例的问题了。但是万恶的老王又TM来了。老王说,hey兄弟,我们的api.jackma.com这个域下的/getdata这个接口需要改一改,老板觉得/getdata有点丑,我们决定改成/getuser。此时你一边在心里问候着老王,一边窃喜,还好写的不多,只需要两个组件的内容。但是仔细一想,善变的老王不一定又会改什么,要是的API用多了岂不是和最开始使用axios出现了相同问题,容易错该,漏改。身为一个优秀的程序员,必须将其抽象。
改造四,将请求url抽象封装
api.js的内容为
import axios from 'axios'
const mozleeAPI = axios.create({
baseURL:'https://api.mozlee.com',
... // 其他config
})
const jackmaAPI = axios.create({
baseURL:'https://api.jackma.com',
... // 其他config
})
export getData(){
return jackmaAPI.get('/getuser')
}
export getData2(){
return jackmaAPI.get('/getdata2')
}
export getData3(){
return mozleeAPI.get('/getdata3')
}
组件A的内容为
<template>
<div id="app">
<button @click="getData">加载数据</button>
<button @click="getData2">加载数据2</button>
<button @click="getData3">加载数据3</button>
</div>
</template>
<script>
import { getData, getData2, getData3 } from './api.js'
export default {
methods:{
getData(){
getData().then({data}=>{
//todo bala bala~
})
},
getData2(){
getData2().then({data}=>{
//todo bala bala~
})
},
getData3(){
getData3().then({data}=>{
//todo bala bala~
})
}
}
}
</script>
组件B的内容为
<template>
<div id="app">
<button @click="getData">加载数据</button>
</div>
</template>
<script>
import { getData } from './api.js'
export default {
methods:{
getData(){
getData().then({data}=>{
//todo bala bala~
})
}
}
}
</script>
如此一来,看你老王还能玩出什么花活!
老王嘿嘿一笑,兄弟,我们的接口要求在api.mozlee.com域的url上带上一个时间time的参数,在api.jackma.com域的请求header中添加一个name:lilei的自定义头。
聪明的你当然不能再接口函数里边一个一个加了。
改造五,使用axios request拦截器
api.js的内容为
import axios from 'axios'
const mozleeAPI = axios.create({
baseURL:'https://api.mozlee.com',
... // 其他config
})
mozleeAPI.interceptors.request.use(function (config) {
config.url += `?time=${new Date().getTime()}`
return config
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error)
})
const jackmaAPI = axios.create({
baseURL:'https://api.jackma.com',
... // 其他config
})
jackmaAPI.interceptors.request.use(function (config) {
config.header = Object.assign(config.header ,{'name':'lilei'})
return config
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error)
})
export getData(){
return jackmaAPI.get('/getuser')
}
export getData2(){
return jackmaAPI.get('/getdata2')
}
export getData3(){
return mozleeAPI.get('/getdata3')
}
这时候的老王确实提不出什么需求了,但是你发现了一个问题。api.jackma.com域的接口一定返回一种约定好格式的json 如下:
{
data:['lilei','hanmeimei'],
stat:1,
msg:'success'
}
每次调用的时候都需要在Promise的then中做一个判断,当stat>0是做成功的事,stat!=0的时候做失败的事。
<template>
<div id="app">
<button @click="getData">加载数据</button>
<button @click="getData2">加载数据2</button>
<button @click="getData3">加载数据3</button>
</div>
</template>
<script>
import { getData, getData2, getData3 } from './api.js'
export default {
methods:{
getData(){
getData().then({data}=>{
if(data.stat>0){
doSuccess()
}else{
doError()
}
}).catch(err=>{
doError()
})
},
getData2(){
getData2().then({data}=>{
if(data.stat>0){
doSuccess()
}else{
doError()
}
}).catch(err=>{
doError()
})
},
getData3(){
getData3().then({data}=>{
if(data.status){
doSuccess()
}else{
doError()
}
}).catch(err=>{
doError()
})
}
}
}
</script>
改造六、使用axios response拦截器。
import axios from 'axios'
const mozleeAPI = axios.create({
baseURL:'https://api.mozlee.com',
... // 其他config
})
mozleeAPI.interceptors.request.use(function (config) {
config.url += `?time=${new Date().getTime()}`
return config
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error)
})
const jackmaAPI = axios.create({
baseURL:'https://api.jackma.com',
... // 其他config
})
jackmaAPI.interceptors.request.use(function (config) {
config.header = Object.assign(config.header ,{'name':'lilei'})
return config
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error)
})
// response 拦截器
jackmaAPI.interceptors.response.use(function ({ data }) {
// 对响应数据做点什么
if (data.stat > 0) {
return data
} else {
return Promise.reject(data)
}
}, function (error) {
console.log(error)
return Promise.reject(error)
})
export getData(){
return jackmaAPI.get('/getuser')
}
export getData2(){
return jackmaAPI.get('/getdata2')
}
export getData3(){
return mozleeAPI.get('/getdata3')
}
只要是非成功状态,不管是网络状态非200,还是200状态但是response结果的stat为0,我们都把他们reject。
这样我们在Promise.then中 只做Success相关,catch中只做错误相关。改造后的 组件代码如下
<template>
<div id="app">
<button @click="getData">加载数据</button>
<button @click="getData2">加载数据2</button>
<button @click="getData3">加载数据3</button>
</div>
</template>
<script>
import { getData, getData2, getData3 } from './api.js'
export default {
methods:{
getData(){
getData().then({data}=>{
doSuccess()
}).catch(err=>{
doError()
})
},
getData2(){
getData2().then({data}=>{
doSuccess()
}).catch(err=>{
doError()
})
},
getData3(){
getData3().then({data}=>{
if(data.status){
doSuccess()
}else{
doError()
}
}).catch(err=>{
doError()
})
}
}
}
</script>
哈哈,这下基本上可以满足老王的任性变动,以及自己开发的复用、简单化开发。
最后的建议
- 一个项目多个域的接口,建议统一管理。建立一个统一的index.js管理不同的域,并且向外暴露axios实例。 index.js
import axios from 'axios'
const mozleeAPI = axios.create({
baseURL:'//api.mozlee.com'
})
const jackmaAPI = axios.create({
baseURL:'//api.jackma.com'
})
const hanmeimeiAPI = axios.create({
baseURL:'//api.hanmeimei.com'
})
export {
mozleeAPI, jackmaAPI,hanmeimeiAPI
}
- 常见需求还有取消请求,可以使用axios相关API。