liveh5-nuxt/app/api/http.js

131 lines
3.1 KiB
JavaScript
Raw Normal View History

import { useRuntimeConfig } from '#app'
import { ofetch} from 'ofetch'
import { message } from '@/components/x-message/useMessage.js'
import { authStore } from "@/stores/auth/index.js"
let httpStatusErrorHandler
let http
// HTTP 状态码映射
const HTTP_STATUS_MAP = {
400: '请求参数错误',
401: '未授权或登录过期',
403: '访问被禁止',
404: '请求的资源不存在',
500: '服务器内部错误',
502: '网关错误',
503: '服务暂时不可用',
504: '网关超时'
}
export function setupHttp() {
if (http) return http
const config = useRuntimeConfig()
const baseURL = config.public.NUXT_PUBLIC_API_BASE
const { token } = authStore()
const router = useRouter()
const defaultOptions = {
baseURL,
headers: { 'Content-Type': 'application/json' },
timeout: 15000, // 15秒超时
retry: 3,
retryDelay: 1000,
}
http = ofetch.create({
...defaultOptions,
// 请求拦截
async onRequest({ options, request }) {
// 添加 token
options.headers = {
...options.headers,
Authorization: token.value
}
// GET 请求添加时间戳防止缓存
if (request.toLowerCase().includes('get')) {
options.params = {
...options.params,
_t: Date.now()
}
}
},
// 响应拦截
async onResponse({ response }) {
const data = response._data
// 处理业务错误
if (data.status === 1) {
message.error(data.msg || '操作失败')
return Promise.reject(new Error(data.msg))
}
// 处理登录失效
if (data.status === 401) {
message.error('登录已过期,请重新登录')
token.value = '' // 清除 token
router.replace('/login')
return Promise.reject(new Error('未登录或登录已过期'))
}
return response
},
// 响应错误处理
async onResponseError({ response, request }) {
// 网络错误
if (!response) {
message.error('网络连接失败,请检查网络设置')
return Promise.reject(new Error('网络错误'))
}
const status = response.status
const data = response._data
// 处理 HTTP 状态错误
const errorMessage = data.msg || HTTP_STATUS_MAP[status] || '请求失败'
if (Array.isArray(data.msg)) {
data.msg.forEach(item => {
httpStatusErrorHandler?.(item, status)
})
} else {
httpStatusErrorHandler?.(errorMessage, status)
}
message.error(errorMessage)
return Promise.reject(data)
},
})
return http
}
export function createAbortController() {
return new AbortController()
}
export function injectHttpStatusErrorHandler(handler) {
httpStatusErrorHandler = handler
}
export function getHttp() {
if (!http) {
throw new Error('HTTP client not initialized. Call setupHttp first.')
}
return http
}
// 导出请求工具函数
export async function request(url, options) {
const http = getHttp()
try {
const response = await http(url, options)
return response.data
} catch (error) {
throw error
}
}