app/src/utils/http.js

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()