Files
FiDA_Front/src/utils/request.ts
2026-02-25 11:00:31 +08:00

184 lines
5.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import axios from 'axios'
import router from '@/router/index'
import { useGlobalStore, useUserInfoStore } from '@/stores'
import { ElMessage } from 'element-plus'
// 扩展 AxiosRequestConfig 接口
declare module 'axios' {
interface AxiosRequestConfig {
loading?: boolean
loadingDom?: any
repeatRequest?: boolean
meta?: {
responseAll?: boolean
}
}
}
// 创建axios实例
// console.log(import.meta.env,123)
const service = axios.create({
// baseURL: import.meta.env.VITE_APP_URL, // api的base_url
timeout: 60000 // 请求超时时间
})
if (import.meta.env.MODE != 'development') {
service.defaults.baseURL = import.meta.env.VITE_APP_URL
}
axios.defaults.headers.post['Content-Type'] = 'application/json'
axios.defaults.headers.post['lang'] = 'en' //配置语言请求头
axios.defaults.withCredentials = true //跨域携带cookie
// request拦截器
service.interceptors.request.use(
(config: any) => {
removePending(config)
// 如果repeatRequest不配置那么默认该请求就取消重复接口请求
!config.repeatRequest && addPending(config)
// 打开loading
if (config.loading) {
LoadingInstance._count++
if (LoadingInstance._count === 1) {
openLoading(config.loadingDom)
}
}
// 如果登录了有token则请求携带token
// Do something before request is sent
const token = useUserInfoStore().state.token
if (token) {
config.headers.Authorization = 'Bearer ' + token // 让每个请求携带token--['X-Token']为自定义key 请根据实际情况自行修改
// config.headers['X-Token'] = getLocal('token') // 让每个请求携带token--['X-Token']为自定义key 请根据实际情况自行修改
}
return config
},
(error) => {
// Do something with request error
console.log(error) // for debug
Promise.reject(error)
}
)
// respone拦截器
service.interceptors.response.use(
// response => response,
/**
* 下面的注释为通过response自定义code来标示请求状态当code返回如下情况为权限有问题登出并返回到登录页
* 如通过xmlhttprequest 状态码标识 逻辑可写在下面error中
*/
(response: any) => {
// 如果是llm/streamChat这样的流式接口,不走这样的处理
if (response.config.url.includes('llm/streamChat')) {
return response
}
// 已完成请求的删除请求中数组
removePending(response.config)
// 关闭loading
if (response.config.loading) {
closeLoading()
}
const res = response.data
// 处理异常的情况
// console.log(res)
if (res.code != 200) {
ElMessage.error(res.message)
return Promise.reject(new Error(res.errMsg || res.message || 'error'))
} else {
// 默认只返回data不返回状态码和message
// 通过 meta 中的 responseAll 配置来取决后台是否返回所有数据(包括状态码message和data)
const isbackAll = response.config.meta && response.config.meta.responseAll
if (isbackAll) {
return res
} else {
return res.data
}
}
},
(error) => {
if (error?.response) {
if (error.config?.loading) closeLoading() // 关闭loading
if (error?.response?.status === 401) {
//如果是记录浏览器页面就不跳转login
// showConfirmDialog({
// title: '确定登出',
// message: '你已被登出,可以取消继续留在该页面,或者重新登录',
// confirmButtonText: '重新登录',
// cancelButtonText: '取消'
// }).then(() => {
// store.loginOut().then(() => {
// location.reload() // 为了重新实例化vue-router对象 避免bug
// })
// })
// showToast({
// message: 'Please log in and try again.',
// duration: 5000
// })
// router.push('/login')
// useGenerateStore().clearGenerateData()
return Promise.reject(false)
}
error.config && removePending(error.config)
console.log('err' + error) // for debug
ElMessage.error(error.message)
}
return Promise.reject(error)
}
)
// --------------------------------取消接口重复请求的函数-----------------------------------
// axios.js
const pendingMap = new Map()
/**
* 生成每个请求唯一的键
* @param {*} config
* @returns string
*/
function getPendingKey(config: any) {
const { url, method, params } = config
let { data } = config
if (typeof data === 'string') data = JSON.parse(data) // response里面返回的config.data是个字符串对象
return [url, method, JSON.stringify(params), JSON.stringify(data)].join('&')
}
/**
* 储存每个请求唯一值, 也就是cancel()方法, 用于取消请求
* @param {*} config
*/
function addPending(config: any) {
const pendingKey = getPendingKey(config)
config.cancelToken =
config.cancelToken ||
new axios.CancelToken((cancel) => {
if (!pendingMap.has(pendingKey)) {
pendingMap.set(pendingKey, cancel)
}
})
}
/**
* 删除重复的请求
* @param {*} config
*/
function removePending(config: any) {
const pendingKey = getPendingKey(config)
if (pendingMap.has(pendingKey)) {
const cancelToken = pendingMap.get(pendingKey)
cancelToken(pendingKey)
pendingMap.delete(pendingKey)
}
}
// ----------------------------------loading的函数-------------------------------
const LoadingInstance: { _count: number } = {
_count: 0
}
function openLoading(loadingDom: any) {
useGlobalStore().setLoading(true)
}
function closeLoading() {
if (LoadingInstance._count > 0) LoadingInstance._count--
if (LoadingInstance._count === 0) {
useGlobalStore().setLoading(false)
}
}
export default service