vue3实战-----二次封装axios和统一管理API接口
1.axios二次封装
在开发项目的时候避免不了与后端进行交互,因此我们需要使用axios插件实现发送网络请求。在开发项目的时候我们经常会把axios进行二次封装。
1.1目的
- 使用请求拦截器,可以在请求拦截器中处理一些业务(开始进度条、请求头携带公共参数)
- 使用响应拦截器,可以在响应拦截器中处理一些业务(进度条结束、简化服务器返回的数据、处理http网络错误)
1.2步骤
在src目录下创建utils/request.ts:
//进行axios二次封装:使用请求与响应拦截器
import axios from 'axios'
import { ElMessage } from 'element-plus'
//引入用户相关的仓库
import useUserStore from '@/store/modules/user'
//第一步:利用axios对象的create方法,去创建axios实例(其他的配置:基础路径、超时的时间)
const request = axios.create({
//基础路径
baseURL: import.meta.env.VITE_APP_BASE_API, //基础路径上会携带/api
timeout: 5000, //超时的时间的设置
})
//第二步:request实例添加请求与响应拦截器
request.interceptors.request.use((config) => {
//获取用户相关的小仓库:获取仓库内部token,登录成功以后携带给服务器
const userStore = useUserStore()
if (userStore.token) {
config.headers.token = userStore.token
}
//config配置对象,headers属性请求头,经常给服务器端携带公共参数
//返回配置对象
return config
})
//第三步:响应拦截器
request.interceptors.response.use(
(response) => {
//成功回调
//简化数据
return response.data
},
(error) => {
//失败回调:处理http网络错误的
//定义一个变量:存储网络错误信息
let message = ''
//http状态码
const status = error.response.status
switch (status) {
case 401:
message = 'TOKEN过期'
break
case 403:
message = '无权访问'
break
case 404:
message = '请求地址错误'
break
case 500:
message = '服务器出现问题'
break
default:
message = '网络出现问题'
break
}
//提示错误信息
ElMessage({
type: 'error',
message,
})
return Promise.reject(error)
},
)
//对外暴露
export default request
2.API接口统一管理
在开发项目的时候,接口可能很多需要统一管理。在src目录下去创建api文件夹去统一管理项目的接口。如下:

src/api/user/index.ts:
//统一管理咱们项目用户相关的接口
import request from '@/utils/request'
import type {
loginFormData,
loginResponseData,
userInfoReponseData,
} from './type'
//项目用户相关的请求地址
enum API {
LOGIN_URL = '/admin/acl/index/login',
USERINFO_URL = '/admin/acl/index/info',
LOGOUT_URL = '/admin/acl/index/logout',
}
//登录接口
export const reqLogin = (data: loginFormData) =>
request.post<any, loginResponseData>(API.LOGIN_URL, data)
//获取用户信息
export const reqUserInfo = () =>
request.get<any, userInfoReponseData>(API.USERINFO_URL)
//退出登录
export const reqLogout = () => request.post<any, any>(API.LOGOUT_URL)
src/api/user/type.ts:
//定义用户相关数据的ts类型
//用户登录接口携带参数的ts类型
export interface loginFormData {
username: string
password: string
}
//定义全部接口返回数据都拥有ts类型
export interface ResponseData {
code: number
message: string
ok: boolean
}
//定义登录接口返回数据类型
export interface loginResponseData extends ResponseData {
data: string
}
//定义获取用户信息返回数据类型
export interface userInfoReponseData extends ResponseData {
data: {
routes: string[]
buttons: string[]
roles: string[]
name: string
avatar: string
}
}
3.使用API
store/modules/user.ts:
//创建用户相关的小仓库
import { defineStore } from 'pinia'
//引入接口
import { reqLogin, reqUserInfo, reqLogout } from '@/api/user'
import type {
loginFormData,
loginResponseData,
userInfoReponseData,
} from '@/api/user/type'
import type { UserState } from './types/type'
//引入操作本地存储的工具方法
import { SET_TOKEN, GET_TOKEN, REMOVE_TOKEN } from '@/utils/token'
//引入路由(常量路由)
import { constantRoute, asnycRoute, anyRoute } from '@/router/routes'
//引入深拷贝方法
//@ts-expect-error
import cloneDeep from 'lodash/cloneDeep'
import router from '@/router'
//用于过滤当前用户需要展示的异步路由
function filterAsyncRoute(asnycRoute: any, routes: any) {
return asnycRoute.filter((item: any) => {
if (routes.includes(item.name)) {
if (item.children && item.children.length > 0) {
//硅谷333账号:product\trademark\attr\sku
item.children = filterAsyncRoute(item.children, routes)
}
return true
}
})
}
//创建用户小仓库
const useUserStore = defineStore('User', {
//小仓库存储数据地方
state: (): UserState => {
return {
token: GET_TOKEN(), //用户唯一标识token
menuRoutes: constantRoute, //仓库存储生成菜单需要数组(路由)
username: '',
avatar: '',
//存储当前用户是否包含某一个按钮
buttons: [],
}
},
//异步|逻辑的地方
actions: {
//用户登录的方法
async userLogin(data: loginFormData) {
//登录请求
const result: loginResponseData = await reqLogin(data)
//登录请求:成功200->token
//登录请求:失败201->登录失败错误的信息
if (result.code == 200) {
//pinia仓库存储一下token
//由于pinia|vuex存储数据其实利用js对象
this.token = result.data as string
//本地存储持久化存储一份
SET_TOKEN(result.data as string)
//能保证当前async函数返回一个成功的promise
return 'ok'
} else {
return Promise.reject(new Error(result.data))
}
},
//获取用户信息方法
async userInfo() {
//获取用户信息进行存储仓库当中[用户头像、名字]
const result: userInfoReponseData = await reqUserInfo()
//如果获取用户信息成功,存储一下用户信息
if (result.code == 200) {
this.username = result.data.name
this.avatar = result.data.avatar
this.buttons = result.data.buttons
//计算当前用户需要展示的异步路由
const userAsyncRoute = filterAsyncRoute(
cloneDeep(asnycRoute),
result.data.routes,
)
//菜单需要的数据整理完毕
this.menuRoutes = [...constantRoute, ...userAsyncRoute, anyRoute]
//目前路由器管理的只有常量路由:用户计算完毕异步路由、任意路由动态追加
;[...userAsyncRoute, anyRoute].forEach((route: any) => {
router.addRoute(route)
})
return 'ok'
} else {
return Promise.reject(new Error(result.message))
}
},
//退出登录
async userLogout() {
//退出登录请求
const result: any = await reqLogout()
if (result.code == 200) {
//目前没有mock接口:退出登录接口(通知服务器本地用户唯一标识失效)
this.token = ''
this.username = ''
this.avatar = ''
REMOVE_TOKEN()
return 'ok'
} else {
return Promise.reject(new Error(result.message))
}
},
},
getters: {},
})
//对外暴露获取小仓库方法
export default useUserStore

1923

被折叠的 条评论
为什么被折叠?



