service/request/request.ts
import axios from 'axios'
import { ElLoading } from 'element-plus'
import type { AxiosRequestConfig, AxiosInstance, AxiosResponse } from 'axios'
import type { ILoadingInstance } from 'element-plus/lib/el-loading/src/loading.type'
// import type { LoadingInstance } from "element-plus/lib/components/loading/src/loading"; // 按需引入
/**
* 封装axios
* 这里使用类进行封装是因为类具有更强的一个封装性
* 比单纯的用函数去进行封装要更好一些
* 使用方式:LWJRequest.get()
*/
// 拦截器类型约束--接口
// 可以让不同的类拥有不同的拦截器,更加灵活
interface InterceptorHooks {
requestInterceptor?: (config: AxiosRequestConfig) => AxiosRequestConfig
requestInterceptorCatch?: (error: any) => any
responseInterceptor?: (response: AxiosResponse) => AxiosResponse
responseInterceptorCatch?: (error: any) => any
}
// 类接口
interface LWJRequestConfig extends AxiosRequestConfig {
showLoading?: boolean
interceptorHooks?: InterceptorHooks
}
// 属性接口
interface LWJData {
data: T
returnCode: string
success: boolean
}
// 封装请求类
class LWJRequest {
config: AxiosRequestConfig
interceptorHooks?: InterceptorHooks
showLoading: boolean
loading?: ILoadingInstance
instance: AxiosInstance
constructor(options: LWJRequestConfig) {
this.config = options
this.interceptorHooks = options.interceptorHooks
this.showLoading = options.showLoading ?? true
this.instance = axios.create(options)
this.setupInterceptor()
}
// 拦截器函数
setupInterceptor(): void {
// 请求拦截
this.instance.interceptors.request.use(
this.interceptorHooks?.requestInterceptor,
this.interceptorHooks?.requestInterceptorCatch
)
// 响应拦截
this.instance.interceptors.response.use(
this.interceptorHooks?.responseInterceptor,
this.interceptorHooks?.responseInterceptorCatch
)
// 添加所有实例都有的拦截器--请求拦截器
this.instance.interceptors.request.use((config) => {
if (this.showLoading) {
this.loading = ElLoading.service({
lock: true,
text: 'Loading',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
})
}
return config
})
// 正在加载效果--响应拦截器
this.instance.interceptors.response.use(
(res) => {
// setTimeout(()=>{
// this.loading?.close()
// },1000)
this.loading?.close()
return res
},
(err) => {
this.loading?.close()
// if(err.response.status === 404){
// }
return err
}
)
}
// 某一个单独的请求拦截器
request(config: LWJRequestConfig): Promise {
if (!config.showLoading) {
this.showLoading = false
}
return new Promise((resolve, reject) => {
this.instance
.request>(config)
.then((res) => {
resolve(res.data)
this.showLoading = true
})
.catch((err) => {
reject(err)
this.showLoading = true
})
})
}
// 封装get请求
get(config: LWJRequestConfig): Promise {
return this.request({ ...config, method: 'GET' })
}
// 封装post请求
post(config: LWJRequestConfig): Promise {
return this.request({ ...config, method: 'POST' })
}
// 封装delete请求
delete(config: LWJRequestConfig): Promise {
return this.request({ ...config, method: 'DELETE' })
}
// 封装patch请求
patch(config: LWJRequestConfig): Promise {
return this.request({ ...config, method: 'PATCH' })
}
}
export default LWJRequest
service/request/config.ts
// 1.区分环境变量方式一:
// export const API_BASE_URL = 'https://coderwhy/org/dev'
// export const API_BASE_URL = 'https://coderwhy/org/prod'
// 2.区分环境变量方式二:
// let baseURL = ''
// if (process.env.NODE_ENV === 'production') {
// baseURL = 'https://coderwhy/org/prod'
// } else if (process.env.NODE_ENV === 'development') {
// baseURL = 'https://coderwhy/org/dev'
// } else {
// baseURL = 'https://coderwhy/org/test'
// }
// 3.区分环境变量方式三: 加载.env文件
export const API_BASE_URL = process.env.VUE_APP_BASE_URL
export const TIME_OUT = 5000
service/request/type.ts
export interface Result {
code: number
data: T
}
service/index.ts
// 统一出口文件
import LWJRequest from "./request/request"
import { API_BASE_URL, TIME_OUT } from './request/config'
import localCache from '@/utils/cache'
const lwjRequest = new LWJRequest({
baseURL: API_BASE_URL,
timeout: TIME_OUT,
// 可以让不同的类拥有不同的拦截器,更加灵活
interceptorHooks: {
// 请求成功拦截
requestInterceptor: (config) => {
const token = localCache.getCache('token')
if (token && config.headers) {
config.headers.Authorization = `Bearer ${token}`
}
return config
},
// 请求失败拦截
requestInterceptorCatch: (err) => {
return err
},
// 响应成功拦截
responseInterceptor: (res) => {
return res.data
},
// 响应失败拦截
responseInterceptorCatch: (err) => {
return err
}
}
})
// export const lwjRequest2 = new LWJRequest({
// baseURL: '地址2'
// })
export default lwjRequest
service/login/login.ts
import lwjRequest from "../index";
import {IAccount,LoginInfo} from './type'
// 枚举
enum LoginAPI {
AccountLogin = 'login',
UserInfo = '/users/',
UserMenus = '/role/'
}
/**
* 登录
* @param account
* @returns
*/
export function accountLoginRequest(account: IAccount){
return lwjRequest.post({
url: LoginAPI.AccountLogin,
data: account
})
}
/**
* 根据id获取用户信息
* @param id
* @returns
*/
export function requestUserInfoById(id: number){
return lwjRequest.get({
url: LoginAPI.UserInfo + id,
})
}
/**
* 根据当前用户id去请求对应的菜单
* @param id
* @returns
*/
export function requestUserMenusByRoleId(id: number) {
return lwjRequest.get({
url: LoginAPI.UserMenus + id + '/menu'
})
}
service/login/type.ts
export interface IAccount {
name: string,
password: string
}
export interface LoginInfo {
id: number,
name: string,
token:string
}
// export interface IDataType {
// id: number,
// token: T
// }
utils/cache.ts
// 封装本地存储方法
class LocalCache {
setCache(key: string, value: any) {
window.localStorage.setItem(key, JSON.stringify(value))
}
getCache(key: string) {
const value = window.localStorage.getItem(key)
if (value) {
return JSON.parse(value)
}
}
deleteCache(key: string) {
window.localStorage.removeItem(key)
}
clearLocal() {
window.localStorage.clear()
}
}
export default new LocalCache()
service/config/index.ts
// 1.区分开发环境和生产环境
// export const BASE_URL = 'http://aaa.dev:8000'
// export const BASE_URL = 'http://aaa.prod:8000'
// 2.代码逻辑判断, 判断当前环境
// vite默认提供的环境变量
// console.log(import.meta.env.MODE)
// console.log(import.meta.env.DEV); // 是否开发环境
// console.log(import.meta.env.PROD); // 是否生产环境
// console.log(import.meta.env.SSR); // 是否是服务器端渲染(server side render)
let BASE_URL = "";
if (import.meta.env.PROD) {
// 生产环境
BASE_URL = "http://152.136.185.210:4000";
} else {
// 开发环境
BASE_URL = "http://152.136.185.210:5000";
}
// console.log(BASE_URL);
// 3.通过创建.env文件直接创建变量
// console.log(import.meta.env.VITE_URL);
export const TIME_OUT = 10000;
export { BASE_URL };
service/request/index.ts
import axios from "axios";
import type { AxiosInstance } from "axios";
import type { LWJRequestConfig } from "./type";
// 拦截器: 蒙版Loading/token/修改配置
/**
* 两个难点:
* 1.拦截器进行精细控制
* > 全局拦截器
* > 实例拦截器
* > 单次请求拦截器
*
* 2.响应结果的类型处理(泛型)
*/
class LWJRequest {
instance: AxiosInstance;
// request实例 => axios的实例
constructor(config: LWJRequestConfig) {
this.instance = axios.create(config);
// 每个instance实例都添加拦截器
this.instance.interceptors.request.use(
(config) => {
// loading/token
return config;
},
(err) => {
return err;
}
);
this.instance.interceptors.response.use(
(res) => {
return res.data;
},
(err) => {
return err;
}
);
// 针对特定的LWJRequest实例添加拦截器
this.instance.interceptors.request.use(
config.interceptors?.requestSuccessFn,
config.interceptors?.requestFailureFn
);
this.instance.interceptors.response.use(
config.interceptors?.responseSuccessFn,
config.interceptors?.responseFailureFn
);
}
// 封装网络请求的方法
// T => IHomeData
request(config: LWJRequestConfig) {
// 单次请求的成功拦截处理
if (config.interceptors?.requestSuccessFn) {
config = config.interceptors.requestSuccessFn(config);
}
// 返回Promise
return new Promise((resolve, reject) => {
this.instance
.request(config)
.then((res) => {
// 单词响应的成功拦截处理
if (config.interceptors?.responseSuccessFn) {
res = config.interceptors.responseSuccessFn(res);
}
resolve(res);
})
.catch((err) => {
reject(err);
});
});
}
get(config: LWJRequestConfig) {
return this.request({ ...config, method: "GET" });
}
post(config: LWJRequestConfig) {
return this.request({ ...config, method: "POST" });
}
delete(config: LWJRequestConfig) {
return this.request({ ...config, method: "DELETE" });
}
patch(config: LWJRequestConfig) {
return this.request({ ...config, method: "PATCH" });
}
}
export default LWJRequest;
service/request/type.ts
import type { AxiosRequestConfig, AxiosResponse } from "axios";
// 针对AxiosRequestConfig配置进行扩展
export interface LWJInterceptors {
requestSuccessFn?: (config: AxiosRequestConfig) => AxiosRequestConfig;
requestFailureFn?: (err: any) => any;
responseSuccessFn?: (res: T) => T;
responseFailureFn?: (err: any) => any;
}
export interface LWJRequestConfig
extends AxiosRequestConfig {
interceptors?: LWJInterceptors;
}
service/index.ts
import { LOGIN_TOKEN } from '@/global/constants'
import { localCache } from '@/utils/cache'
import { BASE_URL, TIME_OUT } from './config'
import LWJRequest from './request'
const lwjRequest = new LWJRequest({
baseURL: BASE_URL,
timeout: TIME_OUT,
interceptors: {
requestSuccessFn: (config) => {
// 每一个请求都自动携带token
const token = localCache.getCache(LOGIN_TOKEN)
if (config.headers && token) {
// 类型缩小
config.headers.Authorization = 'Bearer ' + token
}
return config
}
}
})
export default lwjRequest
src/global/constants.ts
export const LOGIN_TOKEN = 'login/token'
src/utils/cache.ts
enum CacheType {
Local,
Session
}
class Cache {
storage: Storage
constructor(type: CacheType) {
this.storage = type === CacheType.Local ? localStorage : sessionStorage
}
setCache(key: string, value: any) {
if (value) {
this.storage.setItem(key, JSON.stringify(value))
}
}
getCache(key: string) {
const value = this.storage.getItem(key)
if (value) {
return JSON.parse(value)
}
}
removeCache(key: string) {
this.storage.removeItem(key)
}
clear() {
this.storage.clear()
}
}
const localCache = new Cache(CacheType.Local)
const sessionCache = new Cache(CacheType.Session)
export { localCache, sessionCache }
service/login/index.ts
import hyRequest from '..'
import type { IAccount } from '@/types'
// import { localCache } from '@/utils/cache'
// import { LOGIN_TOKEN } from '@/global/constants'
export function accountLoginRequest(account: IAccount) {
return hyRequest.post({
url: '/login',
data: account
})
}
export function getUserInfoById(id: number) {
return hyRequest.get({
url: `/users/${id}`
// headers: {
// Authorization: 'Bearer ' + localCache.getCache(LOGIN_TOKEN)
// }
})
}
export function getUserMenusByRoleId(id: number) {
return hyRequest.get({
url: `/role/${id}/menu`
})
}