Files

136 lines
3.8 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://28j56530c4.oicp.vip'
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: any, config: RequestConfig): ApiResponse<T> | null {
if (config.showLoading !== false) hideLoading()
if (response.statusCode !== 200) {
handleError(response.statusCode, '网络请求失败', config.showError)
return null
}
const rawResult = response.data as any
const result: ApiResponse<T> = {
code: Number(rawResult?.code ?? rawResult?.Code),
message: String(rawResult?.message ?? rawResult?.Message ?? ''),
data: (rawResult?.data ?? rawResult?.Data ?? null) as T | null
}
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 })
}