Files
DinQuant/quantdinger_vue/src/utils/request.js
T

153 lines
5.6 KiB
JavaScript

import axios from 'axios'
// import store from '@/store'
import storage from 'store'
import notification from 'ant-design-vue/es/notification'
import { VueAxios } from './axios'
import { ACCESS_TOKEN } from '@/store/mutation-types'
// PHPSESSID 存储键名
const PHPSESSID_KEY = 'PHPSESSID'
// Locale storage key used by vue-i18n (see src/locales/index.js)
const LOCALE_KEY = 'lang'
// 创建 axios 实例
const request = axios.create({
// API 请求的默认前缀
// 生产环境应由 Nginx 处理,开发环境由 devServer proxy 处理
baseURL: '/',
timeout: 30000, // Default request timeout 30s
withCredentials: true // 允许携带 cookies
})
// Extended timeout for long-running AI analysis APIs
export const ANALYSIS_TIMEOUT = 180000 // 3 minutes for AI analysis
// 异常拦截处理器
const errorHandler = (error) => {
if (error.response) {
const data = error.response.data
if (error.response.status === 403) {
notification.error({
message: '(Demo Mode)',
description: data.msg || data.message || 'Read-only in demo mode'
})
}
if (error.response.status === 401 && !(data.result && data.result.isLogin)) {
notification.error({
message: 'Unauthorized',
description: 'Authorization verification failed'
})
// 不清理本地 token,避免刷新后丢失登录态;仅跳转到登录页
const loginPath = '/user/login'
const cur = window.location.pathname + window.location.search
if (!cur.includes('/user/login')) {
const redirect = encodeURIComponent(cur)
window.location.assign(`${loginPath}?redirect=${redirect}`)
}
}
}
return Promise.reject(error)
}
// request interceptor
request.interceptors.request.use(config => {
const token = storage.get(ACCESS_TOKEN)
const lang = storage.get(LOCALE_KEY) || 'en-US'
// Tell backend which UI language user is using, so AI reports can match it.
// We keep both a custom header and the standard Accept-Language for compatibility.
config.headers['X-App-Lang'] = lang
config.headers['Accept-Language'] = lang
// 如果 token 存在,将 token 添加到请求头
if (token) {
// 使用 Authorization header,格式为 Bearer {token}
config.headers['Authorization'] = `Bearer ${token}`
// 同时保留原有的 Access-Token header(如果后端需要)
config.headers[ACCESS_TOKEN] = token
// 兼容后端要求的 token 头
config.headers['token'] = token
}
// 防止缓存导致的 304:为请求添加禁止缓存的头
config.headers['Cache-Control'] = 'no-cache'
config.headers['Pragma'] = 'no-cache'
config.headers['If-Modified-Since'] = '0'
// 为 GET 请求添加时间戳参数,避免缓存
if ((config.method || 'get').toLowerCase() === 'get') {
const ts = Date.now()
config.params = Object.assign({}, config.params || {}, { _t: ts })
}
// 手动设置 PHPSESSID cookie,确保每次请求使用相同的 session
// 注意:浏览器不允许手动设置 Cookie 请求头,需要通过 document.cookie 设置
// 但由于跨域限制,可能无法直接设置 cookie,主要依赖 withCredentials: true
const phpsessid = storage.get(PHPSESSID_KEY)
if (phpsessid && typeof document !== 'undefined') {
// 检查当前 document.cookie 中的 PHPSESSID
const currentCookies = document.cookie
const currentPhpsessidMatch = currentCookies.match(/PHPSESSID=([^;]+)/i)
const currentPhpsessid = currentPhpsessidMatch ? currentPhpsessidMatch[1].trim() : null
// 如果当前 cookie 中的 PHPSESSID 与保存的不一致,尝试更新
// 注意:跨域情况下可能无法设置 cookie,这取决于 CORS 配置
if (!currentPhpsessid || currentPhpsessid !== phpsessid) {
// 尝试设置 cookie(可能因为跨域而失败,但不影响 withCredentials 的工作)
try {
// 尝试设置带 domain 的 cookie(仅当在相同域名下时有效)
if (window.location.hostname.includes('quantdinger.com')) {
document.cookie = `PHPSESSID=${phpsessid}; path=/; domain=.quantdinger.com; SameSite=None; Secure`
} else {
// 跨域情况下,只能依赖 withCredentials: true 和服务器设置
// 这里尝试设置,但可能不会成功
document.cookie = `PHPSESSID=${phpsessid}; path=/; SameSite=None; Secure`
}
} catch (e) {
// 设置失败是正常的(跨域限制),主要依赖 withCredentials
}
}
}
return config
}, errorHandler)
// response interceptor
request.interceptors.response.use((response) => {
// 从响应中提取 PHPSESSID 并保存
// 由于浏览器安全限制,无法直接读取 set-cookie 头,需要通过 document.cookie 获取
try {
if (typeof document !== 'undefined') {
// 从 document.cookie 获取 PHPSESSID(浏览器自动设置的)
const cookies = document.cookie
const phpsessidMatch = cookies.match(/PHPSESSID=([^;]+)/i)
if (phpsessidMatch && phpsessidMatch[1]) {
const phpsessid = phpsessidMatch[1].trim()
// 保存 PHPSESSID 到 storage,有效期 24 小时
const savedPhpsessid = storage.get(PHPSESSID_KEY)
// 如果 PHPSESSID 发生变化,更新保存的值
if (!savedPhpsessid || savedPhpsessid !== phpsessid) {
storage.set(PHPSESSID_KEY, phpsessid, new Date().getTime() + 24 * 60 * 60 * 1000)
}
}
}
} catch (e) {
}
return response.data
}, errorHandler)
const installer = {
vm: {},
install (Vue) {
Vue.use(VueAxios, request)
}
}
export default request
export {
installer as VueAxios,
request as axios
}