refactor(前端): 重构登录页面和用户状态管理逻辑 fix(后端): 修复用户密码更新逻辑和错误提示 feat(后端): 实现分页搜索功能并优化文件删除逻辑 perf(前端): 优化笔记编辑器自动保存和状态提示 fix(后端): 增强图片上传安全验证 style(前端): 调整笔记预览页面按钮权限控制 chore: 更新生产环境配置和测试数据库依赖 feat(前端): 添加虚拟列表组件优化性能 fix(前端): 修复笔记编辑器返回逻辑和状态保存 refactor(前端): 优化axios拦截器错误处理逻辑 docs: 更新方法注释和参数说明
129 lines
3.4 KiB
JavaScript
129 lines
3.4 KiB
JavaScript
import axios from 'axios'
|
||
import { useUserStore } from '../stores/user'
|
||
import { ElMessage } from 'element-plus'
|
||
import router from '../router'
|
||
import { getReplayAttackHeaders, needsReplayAttackValidation } from './security'
|
||
|
||
let retryCount = 0
|
||
const MAX_RETRIES = 3
|
||
|
||
const instance = axios.create({
|
||
baseURL: import.meta.env.VITE_API_BASE_URL,
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
}
|
||
})
|
||
|
||
// 请求拦截器
|
||
instance.interceptors.request.use(
|
||
config => {
|
||
try {
|
||
const userStore = useUserStore()
|
||
if (userStore.token) {
|
||
config.headers['Authorization'] = `Bearer ${userStore.token}`
|
||
}
|
||
|
||
// 添加 CSRF token
|
||
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.content
|
||
if (csrfToken) {
|
||
config.headers['X-CSRF-Token'] = csrfToken
|
||
}
|
||
|
||
// 添加防重放攻击请求头(POST/PUT/DELETE 请求)
|
||
if (needsReplayAttackValidation(config.method, config.url)) {
|
||
const replayHeaders = getReplayAttackHeaders()
|
||
config.headers['X-Timestamp'] = replayHeaders['X-Timestamp']
|
||
config.headers['X-Nonce'] = replayHeaders['X-Nonce']
|
||
}
|
||
} catch (error) {
|
||
console.warn('Failed to get user store:', error)
|
||
}
|
||
return config
|
||
},
|
||
error => {
|
||
return Promise.reject(error)
|
||
}
|
||
)
|
||
|
||
// 响应拦截器
|
||
instance.interceptors.response.use(
|
||
response => {
|
||
retryCount = 0
|
||
const res = response.data;
|
||
if (res.code !== 200) {
|
||
ElMessage({
|
||
message: res.msg || 'Error',
|
||
type: 'error',
|
||
duration: 5 * 1000
|
||
});
|
||
return Promise.reject(new Error(res.msg || 'Error'));
|
||
} else {
|
||
return res.data;
|
||
}
|
||
},
|
||
async error => {
|
||
if (error.response) {
|
||
const status = error.response.status;
|
||
const data = error.response.data;
|
||
|
||
// 503 - 服务器繁忙,重试
|
||
if (status === 503 && retryCount < MAX_RETRIES) {
|
||
retryCount++
|
||
await new Promise(resolve => setTimeout(resolve, 1000 * retryCount))
|
||
return instance(error.config)
|
||
}
|
||
retryCount = 0
|
||
|
||
// 401 - 未授权
|
||
if (status === 401) {
|
||
try {
|
||
const userStore = useUserStore()
|
||
userStore.logout();
|
||
ElMessage.error('登录已过期,请重新登录');
|
||
router.push('/login');
|
||
} catch (error) {
|
||
console.warn('Failed to get user store:', error)
|
||
}
|
||
return Promise.reject(error);
|
||
}
|
||
|
||
// 403 - 权限不足
|
||
if (status === 403) {
|
||
const msg = data?.msg || '无权操作';
|
||
ElMessage.error(msg);
|
||
return Promise.reject(new Error(msg));
|
||
}
|
||
|
||
// 429 - 请求过于频繁
|
||
if (status === 429) {
|
||
const msg = data?.msg || '请求过于频繁,请稍后再试';
|
||
ElMessage.error(msg);
|
||
return Promise.reject(new Error(msg));
|
||
}
|
||
|
||
// 400 - 验证码错误等
|
||
if (status === 400) {
|
||
const msg = data?.msg || '请求参数错误';
|
||
ElMessage.error(msg);
|
||
return Promise.reject(new Error(msg));
|
||
}
|
||
|
||
// 其他错误
|
||
const isDev = import.meta.env.DEV;
|
||
const msg = isDev
|
||
? (data?.msg || error.message)
|
||
: (data?.msg || '操作失败,请稍后重试');
|
||
ElMessage.error(msg);
|
||
} else {
|
||
ElMessage({
|
||
message: error.message,
|
||
type: 'error',
|
||
duration: 5 * 1000
|
||
});
|
||
}
|
||
return Promise.reject(error);
|
||
}
|
||
)
|
||
|
||
export default instance
|