1.创建一个新的axios实例
2.请求拦截器,如果有token进行头部携带
3.响应拦截器a.剥离无效数据b.处理token失效
4.导出一个函数,调用当前的axios实例发请求,返回值promise
import axios, { AxiosError, type Method } from 'axios'
import { useUserStore } from '@/stores/user' //pinia存储
import router from '@/router'
import { showToast } from 'vant'
//导出基准地址,原因:其他地方不是通过axios发请求的地方用上基准地址
const baseURL = 'https://consult-api.itheima.net/'
const instance = axios.create({
//axios的一些配置,baseUrl timeout
baseURL,
// 基础地址。超时时间
timeout: 10000
})
// 请求拦截器,携带toekn
instance.interceptors.request.use(
//config是请求配置
(config) => {
const store = useUserStore()
if (store.user?.token && config.headers) {
//请求头设置token
config.headers['Authorization'] = `Bearer ${store.user?.token}`
}
return config
},
(err) => Promise.reject(err)
)
// 响应拦截器 ,剥离无效数据,401拦截
instance.interceptors.response.use(
(res) => {
// 后台约定,响应成功,但是code不是10000,是业务逻辑失败
if (res.data?.code !== 10000) {
showToast(res.data?.message || '业务失败')
return Promise.reject(res.data)
}
// 业务逻辑成功,返回成功数据,作为axios成功的结果
return res.data
},
(err) => {
if (err.response.status === 401) {
// 删除用户信息
const store = useUserStore()
store.delUser()
// 跳转登录,带上接口失效所在页面的地址,登录完成后回跳使用
router.push({
path: 'login',
// 将当前页面的完整路径作为值存储在"returnUrl"键下
query: { returnUrl: router.currentRoute.value.fullPath }
})
}
return Promise.reject(err)
}
)
type Data<T> = {
code: number
message: string
data: T
}
// 4. 请求工具函数
const request = <T>(
url: string,
method: Method = 'get',
submitData?: object
) => {
// request<数据类型,数据类型>() 这样才指定了 res.data 的类型
return instance.request<T, Data<T>>({
url,
method,
//1.如果是get请求,需要使用params来传递submitData ?a=10&c=10
//2.如果不是get请求,需要使用data传递submitData 请求体传参
//[]设置一个动态的key,写js表达式,js表达式的执行结果来当key
//methods参数:get,Get,GET转换成消息再来判断
[method.toLocaleLowerCase() === 'get' ? 'params' : 'data']: submitData
})
}
export { instance, baseURL, request }