130 lines
3.6 KiB
TypeScript
130 lines
3.6 KiB
TypeScript
/**
|
|
* 网络请求封装
|
|
* 支持请求拦截、响应拦截、Loading显示、错误处理
|
|
*/
|
|
|
|
export type ApiResponse<T> = {
|
|
code: number
|
|
message: string
|
|
data: T | null
|
|
}
|
|
|
|
export type RequestConfig = {
|
|
url: string
|
|
method?: 'GET' | 'POST' | 'PUT' | 'DELETE'
|
|
data?: any
|
|
header?: any
|
|
showLoading?: boolean
|
|
loadingText?: string
|
|
showError?: boolean
|
|
}
|
|
|
|
const BASE_URL = 'https://localhost:7145'
|
|
const TIMEOUT = 10000
|
|
let loadingCount = 0
|
|
|
|
function showLoading(text: string = '加载中...') {
|
|
loadingCount++
|
|
if (loadingCount === 1) {
|
|
uni.showLoading({ title: text, mask: true })
|
|
}
|
|
}
|
|
|
|
function hideLoading() {
|
|
loadingCount--
|
|
if (loadingCount <= 0) {
|
|
loadingCount = 0
|
|
uni.hideLoading()
|
|
}
|
|
}
|
|
|
|
function getToken(): string {
|
|
return uni.getStorageSync('token') as string ?? ''
|
|
}
|
|
|
|
function requestInterceptor(config: RequestConfig): RequestConfig {
|
|
if (!config.url.startsWith('http')) config.url = BASE_URL + config.url
|
|
|
|
const token = getToken()
|
|
config.header = config.header ?? {}
|
|
config.header['Content-Type'] = 'application/json'
|
|
if (token) config.header['Authorization'] = `Bearer ${token}`
|
|
|
|
if (config.showLoading !== false) showLoading(config.loadingText)
|
|
return config
|
|
}
|
|
|
|
function responseInterceptor<T>(response: UniNamespace.RequestSuccessCallbackResult, config: RequestConfig): ApiResponse<T> | null {
|
|
if (config.showLoading !== false) hideLoading()
|
|
|
|
if (response.statusCode !== 200) {
|
|
handleError(response.statusCode, '网络请求失败', config.showError)
|
|
return null
|
|
}
|
|
|
|
const result = response.data as ApiResponse<T>
|
|
if (result.code !== 200) {
|
|
handleError(result.code, result.message, config.showError)
|
|
return null
|
|
}
|
|
return result
|
|
}
|
|
|
|
function handleError(code: number, message: string, showError: boolean = true) {
|
|
console.error(`[Request Error] Code: ${code}, Message: ${message}`)
|
|
if (!showError) return
|
|
|
|
let errorMsg = message
|
|
if (code === 401) {
|
|
errorMsg = '登录已过期,请重新登录'
|
|
uni.removeStorageSync('token')
|
|
uni.removeStorageSync('userInfo')
|
|
uni.reLaunch({ url: '/pages/login/index' })
|
|
} else if (code === 403) {
|
|
errorMsg = '没有权限访问'
|
|
} else if (code === 404) {
|
|
errorMsg = '请求的资源不存在'
|
|
} else if (code === 500) {
|
|
errorMsg = '服务器错误,请稍后重试'
|
|
} else if (code === -1) {
|
|
errorMsg = '网络异常'
|
|
}
|
|
|
|
uni.showToast({ title: errorMsg, icon: 'none', duration: 2000 })
|
|
}
|
|
|
|
export function request<T>(config: RequestConfig): Promise<ApiResponse<T> | null> {
|
|
return new Promise((resolve) => {
|
|
const finalConfig = requestInterceptor(config)
|
|
uni.request({
|
|
url: finalConfig.url,
|
|
method: finalConfig.method ?? 'GET',
|
|
data: finalConfig.data,
|
|
header: finalConfig.header,
|
|
timeout: TIMEOUT,
|
|
success: (res) => resolve(responseInterceptor<T>(res, finalConfig)),
|
|
fail: (err) => {
|
|
if (finalConfig.showLoading !== false) hideLoading()
|
|
handleError(-1, err.errMsg ?? '网络连接失败', finalConfig.showError)
|
|
resolve(null)
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
export function get<T>(url: string, data?: any, config?: Partial<RequestConfig>): Promise<ApiResponse<T> | null> {
|
|
return request<T>({ url, method: 'GET', data, ...config })
|
|
}
|
|
|
|
export function post<T>(url: string, data?: any, config?: Partial<RequestConfig>): Promise<ApiResponse<T> | null> {
|
|
return request<T>({ url, method: 'POST', data, ...config })
|
|
}
|
|
|
|
export function put<T>(url: string, data?: any, config?: Partial<RequestConfig>): Promise<ApiResponse<T> | null> {
|
|
return request<T>({ url, method: 'PUT', data, ...config })
|
|
}
|
|
|
|
export function del<T>(url: string, data?: any, config?: Partial<RequestConfig>): Promise<ApiResponse<T> | null> {
|
|
return request<T>({ url, method: 'DELETE', data, ...config })
|
|
}
|