说明:axios负责发送请求,mockjs负责便捷构造响应数据,axios-mock-adapter负责代理axios数据请求到本地
很久没更新这篇文章了,目前新写了一篇,推荐这种方式:juejin.cn/post/734801…
目录结构:
1.安装axios+mockjs+axios-mock-adapter
npm i axios mockjs axios-mock-adapter
2.封装axios
import axios from 'axios'
import type {
AxiosInstance,
AxiosError,
AxiosRequestConfig,
AxiosResponse,
} from 'axios'
import { ElMessage } from 'element-plus'
import { useUserStore } from '@/store/modules/user'
import { ResultEnum } from '@/enums/httpEnums'
import { ResultData } from './type'
import { LOGIN_URL } from '@/config/config'
import { RESEETSTORE } from '../reset'
import router from '@/router'
import { initMock } from '@/mock/mock'
export enum ResultEnum {
SUCCESS = 200,
EXPIRE = 203,
ERROR = -1,
ERRMESSAGE = '请求失败',
TIMEOUT = 25000,
TYPE = 'success',
}
export const service: AxiosInstance = axios.create({
// 判断环境设置不同的baseURL
baseURL:
import.meta.env.NODE_ENV === 'development'
? import.meta.env.VITE_APP_BASE_API
: import.meta.env.VITE_APP_BASE_URL,
timeout: ResultEnum.TIMEOUT as number,
})
// 根据配置决定是否使用mock
if (import.meta.env?.VITE_APP_OPEN_MOCK?.toString() === 'true') {
// 初始化mock,axios-mock-adapter
console.log('初始化mock,axios-mock-adapter')
initMock(service)
}
/**
* @description: 请求拦截器
* @returns {*}
*/
service.interceptors.request.use(
(config) => {
const userStore = useUserStore()
const token = userStore.token
if (token) {
config.headers.token = token
}
return config
},
(error: AxiosError) => {
ElMessage.error(error.message)
return Promise.reject(error)
},
)
/**
* @description: 响应拦截器
* @returns {*}
*/
service.interceptors.response.use(
(response: AxiosResponse) => {
const { data } = response
// * 登陆失效(code == 203)
if (data.code === ResultEnum.EXPIRE) {
RESEETSTORE()
ElMessage.error(data.message || ResultEnum.ERRMESSAGE)
router.replace(LOGIN_URL)
return Promise.reject(data)
}
if (data.code && data.code !== ResultEnum.SUCCESS) {
ElMessage.error(data.message || ResultEnum.ERRMESSAGE)
return Promise.reject(data)
}
return data
},
(error: AxiosError) => {
// 处理 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 = '网络连接故障'
}
ElMessage.error(message)
return Promise.reject(error)
},
)
/**
* @description: 导出封装的请求方法
* @returns {*}
*/
const http = {
get<T>(
url: string,
params?: object,
config?: AxiosRequestConfig,
): Promise<ResultData<T>> {
return service.get(url, { params, ...config })
},
post<T>(
url: string,
data?: object,
config?: AxiosRequestConfig,
): Promise<ResultData<T>> {
return service.post(url, data, config)
},
put<T>(
url: string,
data?: object,
config?: AxiosRequestConfig,
): Promise<ResultData<T>> {
return service.put(url, data, config)
},
delete<T>(
url: string,
data?: object,
config?: AxiosRequestConfig,
): Promise<ResultData<T>> {
return service.delete(url, { data, ...config })
},
}
export default http
3.具体实现代码
1.mock.ts
import MockAdapter from 'axios-mock-adapter'
import Mock from 'mockjs'
import { AxiosInstance } from 'axios'
import { resultSuccess } from '@/mock/_utils'
// 引入所有的mock/api中的文件 匹配所有以.ts结尾的文件,但不包括文件名包含"resInfo"的文件
const modules = import.meta.glob('@/mock/api/**/!(*resInfo).ts')
let mock: MockAdapter | null
/**
* @description: 初始化mock
* @param axiosInstance
* @param delayResponse
*/
export function initMock(axiosInstance: AxiosInstance, delayResponse = 1000) {
// 注册所有modules中的mock
mock = new MockAdapter(axiosInstance, { delayResponse })
Object.keys(modules).forEach((key) => modules[key]())
return mock
}
/**
* @description: 使用mock
*/
export function useMock() {
if (!mock) {
throw new Error('Mock not initialized')
} else {
return mock
}
}
/**
* @description: 使用mock onAny
*/
export function useMockOnAny() {
if (!mock) {
throw new Error('Mock not initialized')
} else {
return (url: string, data: any) => {
return mock?.onAny(url).reply(() => {
return new Promise((resolve) => {
console.log(url, resultSuccess(data))
resolve([200, resultSuccess(data)])
})
})
}
}
}
/**
* @description: 使用Mock来模拟数据
* @param data
*/
export function constructMockData<T>(data: T): T {
return Mock.mock(data)
}
2._utils.ts
/*
* @Author: cqq 945327638@qq.com
* @Date: 2023-06-02 10:58:21
* @LastEditors: cqq 945327638@qq.com
* @LastEditTime: 2023-06-02 18:00:01
* @FilePath: \InvestmentAdmin\src\mock_utils.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import { ResultEnum } from '@/enums/httpEnums'
/**
* @description: 错误响应结构
* @returns {*}
*/
export function resultError(
message = 'Request failed',
{ code = ResultEnum.ERROR, data = null } = {},
) {
return {
code,
data,
message,
type: 'error',
}
}
/**
* @description: 成功响应结构
* @returns {*}
*/
export function resultSuccess<T>(data: T, { message = 'ok' } = {}) {
return {
code: ResultEnum.SUCCESS,
data,
message,
type: 'success',
}
}
export interface requestParams {
method: string
body: any
headers?: { authorization?: string }
query: any
}
/**
* @description 本函数用于从request数据中获取token,请根据项目的实际情况修改
* @return token
*/
export function getRequestToken({
headers,
}: requestParams): string | undefined {
return headers?.authorization
}
3.api/user/user
import { useMockOnAny } from '@/mock/mock'
import { loginInfoRes, userInfoRes } from '@/mock/api/user/resInfo'
const mockOnAny = useMockOnAny()
console.log('我被执行了')
// 登陆
mockOnAny('/admin/system/securityLogin/login', loginInfoRes)
// 获取用户信息
mockOnAny('/admin/system/index/info', userInfoRes)
// 退出登陆
mockOnAny('/admin/system/index/logout', {})
4.api/user/resInfo
import { constructMockData } from '@/mock/mock'
// 登陆信息
export const loginInfoRes = constructMockData({
token: 'eyJhbGciOiJIUzUxMiIsInppcCI6IkdaSVAifQ',
})
// 用户信息
export const userInfoRes = constructMockData({
buttons: [],
roles: [],
name: '@name',// 使用mock语法
avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
routers: [],
})
4.使用,直接使用axios发送即可
import http from '@/utils/http'
import type { LoginData, UserRes } from './types'
/* 登录接口参数类型 */
export interface LoginData {
username: string
password: string
}
export interface UserRes {
userId?: string
name: string
avatar: string
buttons: string[]
roles: string[]
routers: Menu.MenuOptions[]
}
/** 用户权限数据类型 */
export interface AuthInfo {
buttons: string[]
roles: string[]
routers: Menu.MenuOptions[]
}
/* 用户信息接口返回值类型 */
export interface UserInfo {
userId?: string
name: string
avatar: string
}
/**
* 登录
*/
export function login(data: LoginData) {
return http.post<{ token: string }>('/admin/system/securityLogin/login', data)
}
/**
* 获取登录用户信息
*/
export function getUserInfo() {
return http.get<UserRes>('/admin/system/index/info')
}
/**
* 退出登陆
*/
export function logout() {
return http.post('/admin/system/index/logout')
}