137 lines
3.4 KiB
JavaScript
137 lines
3.4 KiB
JavaScript
class Request {
|
|
constructor() {
|
|
// 全局默认配置
|
|
this.config = {
|
|
baseURL: import.meta.env.VITE_API_BASE,
|
|
timeout: 10000,
|
|
header: {
|
|
'Content-Type': 'application/json'
|
|
}
|
|
}
|
|
|
|
// 开发环境打印日志
|
|
if (import.meta.env.VITE_DEBUG_MODE === 'true') {
|
|
this._enableDebugLog()
|
|
}
|
|
|
|
// 拦截器存储
|
|
this.interceptors = {
|
|
request: [],
|
|
response: []
|
|
}
|
|
|
|
// 请求队列(用于取消请求)
|
|
this.pendingRequests = new Map()
|
|
}
|
|
|
|
// 调试日志
|
|
_enableDebugLog() {
|
|
const originalRequest = this.request
|
|
this.request = async function(config) {
|
|
console.log('[HTTP Request]', config)
|
|
const start = Date.now()
|
|
try {
|
|
const res = await originalRequest.call(this, config)
|
|
console.log(`[HTTP Response] ${Date.now() - start}ms`, res)
|
|
return res
|
|
} catch (err) {
|
|
console.error(`[HTTP Error] ${Date.now() - start}ms`, err)
|
|
throw err
|
|
}
|
|
}
|
|
}
|
|
|
|
// 小程序 HTTPS 强制转换
|
|
_fixUrlProtocol(url) {
|
|
// #ifdef MP-WEIXIN
|
|
return url.replace(/^http:/, 'https:')
|
|
// #else
|
|
return url
|
|
// #endif
|
|
}
|
|
// 核心请求方法
|
|
async _request(config) {
|
|
// 合并配置
|
|
const mergedConfig = {
|
|
...this.config,
|
|
...config,
|
|
url: this._fixUrlProtocol(config.url)
|
|
}
|
|
|
|
// 生成请求标识
|
|
const requestKey = `${mergedConfig.method}-${mergedConfig.url}`
|
|
const controller = new AbortController()
|
|
this.pendingRequests.set(requestKey, controller)
|
|
|
|
// 构建完整URL
|
|
const fullUrl = `${mergedConfig.baseURL}${mergedConfig.url}`
|
|
|
|
return new Promise((resolve, reject) => {
|
|
uni.request({
|
|
...mergedConfig,
|
|
url: fullUrl,
|
|
signal: controller.signal,
|
|
success: (res) => resolve(res),
|
|
fail: (err) => reject(err)
|
|
})
|
|
})
|
|
}
|
|
|
|
// 执行拦截器链
|
|
async _runInterceptors(type, value) {
|
|
let chain = type === 'request'
|
|
? [...this.interceptors.request, this._request, undefined]
|
|
: [undefined, ...this.interceptors.response]
|
|
|
|
let promise = Promise.resolve(value)
|
|
for (let i = 0; i < chain.length; i += 2) {
|
|
const thenFn = chain[i]
|
|
const catchFn = chain[i + 1]
|
|
promise = promise.then(thenFn, catchFn)
|
|
}
|
|
return promise
|
|
}
|
|
|
|
// 公开请求方法
|
|
async request(config) {
|
|
try {
|
|
// 执行请求拦截
|
|
const processedConfig = await this._runInterceptors('request', config)
|
|
// 发起请求
|
|
const response = await this._request(processedConfig)
|
|
// 执行响应拦截
|
|
return this._runInterceptors('response', response)
|
|
} catch (error) {
|
|
// 统一错误处理
|
|
this._handleError(error)
|
|
return Promise.reject(error)
|
|
}
|
|
}
|
|
|
|
// 快捷方法
|
|
get(url, config = {}) {
|
|
return this.request({ ...config, url, method: 'GET' })
|
|
}
|
|
|
|
post(url, data, config = {}) {
|
|
return this.request({ ...config, url, data, method: 'POST' })
|
|
}
|
|
|
|
// 错误处理
|
|
_handleError(error) {
|
|
let message = '请求失败'
|
|
if (error.errMsg?.includes('timeout')) message = '网络超时'
|
|
if (error.statusCode === 404) message = '接口不存在'
|
|
uni.showToast({ title: message, icon: 'none' })
|
|
}
|
|
|
|
// 取消请求
|
|
cancelRequest(url, method = 'GET') {
|
|
const key = `${method}-${url}`
|
|
const controller = this.pendingRequests.get(key)
|
|
controller?.abort()
|
|
this.pendingRequests.delete(key)
|
|
}
|
|
}
|
|
|
|
export const http = new Request() |