- VideoNode upload now goes through backend (/jobs/upload via uploadCanvasVideo) for a stable reloadable URL instead of a session-only blob: that leaked and broke on reload; cleanNodeForStorage also strips blob: URLs - useCachedMediaUrl: record real blob.size (chunked videos reported 0, making the LRU byte cap a no-op); guard the catch path with the race token - useApi: send credentials when reading reference images; drop the node-level video poll that duplicated the Canvas-level syncPendingVideoNodes loop - request.js: 60s timeout (was ~8.3h) + withCredentials - remove dead getVideoTaskStatus/pollVideoTask that ignored taskId Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
92 lines
2.2 KiB
JavaScript
92 lines
2.2 KiB
JavaScript
/**
|
|
* HTTP Request Utility | HTTP 请求工具
|
|
* Axios-based request with interceptors
|
|
*/
|
|
|
|
import axios from 'axios'
|
|
|
|
// Base URL from environment or default
|
|
// Create axios instance | 创建 axios 实例
|
|
const instance = axios.create({
|
|
baseURL: "/api",
|
|
// 60s default (the old 30000000ms ≈ 8.3h was effectively no timeout, so a hung
|
|
// request would never abort). Send the auth cookie for cross-origin API bases.
|
|
timeout: 60000,
|
|
withCredentials: true
|
|
})
|
|
|
|
// Request interceptor | 请求拦截器
|
|
instance.interceptors.request.use(
|
|
(config) => {
|
|
return config
|
|
},
|
|
(error) => {
|
|
console.error('Request error:', error)
|
|
return Promise.reject(error)
|
|
}
|
|
)
|
|
|
|
// Response interceptor | 响应拦截器
|
|
instance.interceptors.response.use(
|
|
(res) => {
|
|
const { data, code, message } = res.data || {}
|
|
|
|
// Handle stream response | 处理流响应
|
|
if (res.config.responseType === 'stream') {
|
|
return res.data
|
|
}
|
|
|
|
// Handle blob response | 处理 blob 响应
|
|
if (res.data instanceof Blob) {
|
|
return res.data
|
|
}
|
|
|
|
// Success response | 成功响应
|
|
if (code === 200 || res.status === 200) {
|
|
return res.data
|
|
}
|
|
|
|
// Error response | 错误响应
|
|
window.$message?.error(message || 'Request failed')
|
|
return Promise.reject(res.data)
|
|
},
|
|
(error) => {
|
|
const { response } = error
|
|
|
|
if (response) {
|
|
const { status, data } = response
|
|
const message = data?.message || data?.error?.message || error.message
|
|
|
|
if (status === 401) {
|
|
window.$message?.error('登录已过期,请重新进入工作台')
|
|
} else if (status === 429) {
|
|
window.$message?.error('请求过于频繁,请稍后再试')
|
|
} else {
|
|
window.$message?.error(message || '请求失败')
|
|
}
|
|
} else {
|
|
window.$message?.error(error.message || '网络错误')
|
|
}
|
|
|
|
return Promise.reject(error)
|
|
}
|
|
)
|
|
|
|
/**
|
|
* Set API base URL | 设置 API 基础 URL
|
|
* @param {string} url - Base URL
|
|
*/
|
|
export const setBaseUrl = (url) => {
|
|
instance.defaults.baseURL = url
|
|
}
|
|
|
|
/**
|
|
* Get current base URL | 获取当前基础 URL
|
|
* @returns {string}
|
|
*/
|
|
export const getBaseUrl = () => {
|
|
return instance.defaults.baseURL
|
|
}
|
|
|
|
export default instance
|