Files
xian_vue_new/src/utils/request/http.ts
T
wzy-warehouse b87a0e71db Initial commit
2026-04-07 20:01:06 +08:00

149 lines
5.1 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, { type InternalAxiosRequestConfig, type AxiosResponse } from 'axios'
import configJson from '@/config/config.json'
import { SafetyUtils } from '../safety/SafetyUtils.ts'
import { ElMessage } from 'element-plus'
import router from '@/router'
// 扩展Axios内部配置类型
declare module 'axios' {
interface InternalAxiosRequestConfig {
__sm4Key?: string
isNoEncryptUrl?: boolean
}
}
const httpInstance = axios.create({
baseURL: configJson.apiBaseUrl,
timeout: 15000, // 增加超时时间
withCredentials: true,
})
// 请求拦截器
httpInstance.interceptors.request.use(
async (config: InternalAxiosRequestConfig): Promise<InternalAxiosRequestConfig> => {
const { url, method } = config
// 初始化headers
config.headers = config.headers || {}
// 加密处理标记
const isNoEncryptUrl = configJson.noEncryptUrls.some((path) => url?.includes(path))
config.isNoEncryptUrl = isNoEncryptUrl
if (!isNoEncryptUrl) {
try {
// 生成SM4密钥并加密,无论是否有业务参数
const sm4Key = SafetyUtils.generateSm4Key()
config.__sm4Key = sm4Key
const sm4KeyEncrypted = await SafetyUtils.sm2Encrypt(sm4Key)
// GET请求:处理URL参数(无论是否有params,都要传递sm4KeyEncrypted
if (method?.toUpperCase() === 'GET') {
// 有业务参数则加密,无参数则仅传递sm4KeyEncrypted
const encryptedParams = config.params ? SafetyUtils.sm4Encrypt(sm4Key, config.params) : '' // 无参数时encryptedData可为空
config.params = {
encryptedData: encryptedParams,
sm4KeyEncrypted: sm4KeyEncrypted,
}
}
// POST/PUT/DELETE/PATCH请求:处理请求体(无论是否有data,都要传递sm4KeyEncrypted
if (['POST', 'PUT', 'DELETE', 'PATCH'].includes(method?.toUpperCase() || '')) {
if (config.data instanceof FormData) {
// 加密表单数据
const encryptedFormData = SafetyUtils.encryptFormData(sm4Key, config.data)
const newFormData = new FormData()
// 复制加密后的业务字段
for (const [key, value] of encryptedFormData.entries()) {
newFormData.append(key, value)
}
// 强制添加sm4KeyEncrypted
newFormData.append('sm4KeyEncrypted', sm4KeyEncrypted)
config.data = newFormData
} else {
// 有业务数据则加密,无数据则encryptedData为空
const encryptedData = config.data ? SafetyUtils.sm4Encrypt(sm4Key, config.data) : ''
config.data = {
encryptedData: encryptedData,
sm4KeyEncrypted: sm4KeyEncrypted,
}
}
}
} catch (error) {
console.error('请求加密失败:', error)
return Promise.reject(new Error('请求数据加密失败'))
}
}
return config
},
(error) => {
console.error('请求拦截器错误:', error)
return Promise.reject(error)
},
)
// 响应拦截器
httpInstance.interceptors.response.use(
(response: AxiosResponse) => {
const { config, data } = response
let processedData // 用于存储处理后(原始或解密)的数据
// 处理非加密接口或无密钥的情况
if (config.isNoEncryptUrl || !config.__sm4Key) {
processedData = data
} else {
// 处理加密接口的解密逻辑
try {
if (typeof data === 'string') {
// 解密字符串类型的加密数据
processedData = SafetyUtils.sm4Decrypt(config.__sm4Key, data)
} else if (data && typeof data === 'object') {
// 解密对象中包含的加密字段
processedData = SafetyUtils.sm4Decrypt(config.__sm4Key, data.encryptedData || data)
} else {
// 非预期数据格式直接使用原始数据
processedData = data
}
} catch (error) {
console.error('响应数据解密失败:', error)
ElMessage.error('数据解密失败,请重试')
return Promise.reject(new Error('数据解密失败,请重试'))
}
}
// 统一判断处理后的数据状态
if (processedData?.code === 200 || processedData?.code === 409) {
return processedData
} else if (processedData?.code == 401) {
router.push(`/login?redirect=${router.currentRoute.value.fullPath}`)
ElMessage.error('请先登录')
} else {
const errorMsg = processedData?.message || '操作失败,请稍后重试'
ElMessage.error(errorMsg)
return Promise.reject(new Error(errorMsg))
}
},
(error) => {
console.error('响应拦截器错误:', error)
let errorMsg = '请求失败,请稍后重试'
// 处理服务器解密相关错误
if (error.response?.status === 500 && error.response?.data?.msg?.includes('解密')) {
errorMsg = '服务器解密失败,请检查密钥配置'
} else if (error.message) {
// 使用错误对象自带的消息
errorMsg = error.message
}
// 错误提示
ElMessage.error(errorMsg)
return Promise.reject(error)
},
)
export default httpInstance