vitesse-yitisheng-web/src/service/request/index.ts

153 lines
4.4 KiB
TypeScript

import axios, { type AxiosInstance, type AxiosRequestConfig, type AxiosResponse } from 'axios'
import NProgress from 'nprogress'
import CryptoJS from 'crypto-js'
import { useUserStore } from '~/stores/user'
import message from '~/utils/message'
import loading from '~/utils/loading'
import { InternalAxiosRequestConfig } from 'axios'
interface CustomRequestConfig extends InternalAxiosRequestConfig {
showLoading?: boolean,
showError?: boolean
}
interface RequestConfig extends AxiosRequestConfig {
showLoading?: boolean,
showError?: boolean
}
interface ApiResponse<T = any> {
code: number
message: string
data: T
}
class Request {
private instance: AxiosInstance
constructor(config: AxiosRequestConfig) {
this.instance = axios.create(config)
// Request interceptor
this.instance.interceptors.request.use(
(config: InternalAxiosRequestConfig & { showLoading?: boolean }) => {
const customConfig = config as CustomRequestConfig
// NProgress runs by default for visual feedback
NProgress.start()
// Full screen blocking loading controlled by showLoading parameter
if (customConfig.showLoading) {
loading.show()
}
const userStore = useUserStore()
customConfig.headers = customConfig.headers || {}
if (userStore.token) {
customConfig.headers['Authorization'] = 'Bearer ' + userStore.token
}
// Add Signature
const timestamp = Date.now().toString()
const secret = import.meta.env.VITE_API_SECRET || ''
const sign = CryptoJS.MD5(timestamp + secret).toString()
customConfig.headers['X-App-Sign'] = sign
customConfig.headers['X-App-Timestamp'] = timestamp
return customConfig
},
(error) => {
return Promise.reject(error)
}
)
// Response interceptor
this.instance.interceptors.response.use(
(response: AxiosResponse<ApiResponse>) => {
const config = response.config as CustomRequestConfig
NProgress.done()
if (config.showLoading) {
loading.hide()
}
const res = response.data
if (res.code === 200) {
return res.data
} else {
if (config.showError !== false) {
message.error(res.message || 'Error')
}
return Promise.reject(new Error(res.message || 'Error'))
}
},
(error) => {
const config = error.config as CustomRequestConfig
NProgress.done()
if (config?.showLoading) {
loading.hide()
}
let msg = 'Network Error'
if (error.response) {
// 优先使用后端返回的错误信息
const backendMsg = error.response.data?.message
switch (error.response.status) {
case 401:
msg = backendMsg || 'Unauthorized'
const userStore = useUserStore()
userStore.clearToken()
userStore.clearUserInfo()
window.location.href= '/'
// userStore.logout()
// router push login?
break
case 403:
msg = backendMsg || 'Forbidden'
break
case 404:
msg = backendMsg || 'Not Found'
break
case 429:
msg = backendMsg || 'Too Many Requests'
break
case 500:
msg = backendMsg || 'Internal Server Error'
break
default:
msg = backendMsg || `Error: ${error.response.status}`
}
} else if (error.request) {
msg = 'No response from server'
}
if (config?.showError !== false) {
message.error(msg)
}
return Promise.reject(error)
}
)
}
request<T = any>(config: RequestConfig): Promise<T> {
return this.instance.request(config)
}
get<T = any>(url: string, config?: RequestConfig): Promise<T> {
return this.instance.get(url, config)
}
post<T = any>(url: string, data?: any, config?: RequestConfig): Promise<T> {
return this.instance.post(url, data, config)
}
}
export default new Request({
baseURL: import.meta.env.VITE_API_BASE_URL,
timeout: 10000,
})