video-flow-b/api/common.ts
2025-07-03 01:46:58 +08:00

156 lines
4.5 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.

// Common API 相关接口
import { BASE_URL } from './constants'
export interface ApiResponse<T = any> {
code: number
successful: boolean
message: string
data: T
}
export interface TokenResponse {
code: number
message: string
data: {
token: string
}
successful: boolean
}
export interface TokenWithDomainResponse {
code: number
message: string
data: {
token: string
domain: string
}
successful: boolean
}
export interface QiniuUploadResponse {
hash: string
key: string
url?: string
}
// 获取七牛云上传token包含domain
export const getUploadToken = async (timeoutMs: number = 10000): Promise<{ token: string, domain: string }> => {
// 添加超时控制
const controller = new AbortController()
const timeoutId = setTimeout(() => {
console.log(`请求超时(${timeoutMs / 1000}秒),正在中断请求...`)
controller.abort()
}, timeoutMs)
try {
const response = await fetch(`${BASE_URL}/common/get-upload-token`, {
method: "GET",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
signal: controller.signal,
mode: "cors",
})
// 请求完成后清除超时
clearTimeout(timeoutId)
if (!response.ok) {
const errorText = await response.text()
console.error("获取token响应错误:", response.status, errorText)
throw new Error(`获取token失败: ${response.status} ${response.statusText}`)
}
const result: TokenWithDomainResponse | TokenResponse = await response.json()
console.log("获取token响应:", result)
if (result.code === 0 && result.successful && result.data.token) {
console.log("成功获取token")
// Support both old and new API response formats
const domain = 'domain' in result.data ? result.data.domain : 'cdn.qikongjian.com'
return {
token: result.data.token,
domain: domain
}
} else {
throw new Error(result.message || "获取token失败服务器未返回有效token")
}
} catch (error) {
clearTimeout(timeoutId)
console.error("获取上传token失败:", error)
if (error instanceof Error) {
if (error.name === "AbortError") {
throw new Error("请求超时,请检查网络连接")
} else if (error.message.includes("Failed to fetch")) {
throw new Error("网络连接失败可能是CORS策略限制或服务器不可达")
}
}
throw error
}
}
// 生成唯一文件名
export const generateUniqueFileName = (originalName: string): string => {
const timestamp = Date.now()
const randomStr = Math.random().toString(36).substring(2, 8)
const extension = originalName.split(".").pop()
return `videos/${timestamp}_${randomStr}.${extension}`
}
// 七牛云上传
export const uploadToQiniu = async (
file: File,
token: string,
onProgress?: (progress: number) => void
): Promise<string> => {
const uniqueFileName = generateUniqueFileName(file.name)
const formData = new FormData()
formData.append("token", token)
formData.append("key", uniqueFileName)
formData.append("file", file)
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.upload.addEventListener("progress", (event) => {
if (event.lengthComputable && onProgress) {
const progress = Math.round((event.loaded / event.total) * 100)
onProgress(progress)
}
})
xhr.addEventListener("load", () => {
if (xhr.status >= 200 && xhr.status < 300) {
try {
const response: QiniuUploadResponse = JSON.parse(xhr.responseText)
const qiniuUrl = `https://cdn.qikongjian.com/${response.key || uniqueFileName}`
console.log("七牛云上传成功:", response)
resolve(qiniuUrl)
} catch (error) {
console.error("解析响应失败:", error, "原始响应:", xhr.responseText)
reject(new Error(`解析上传响应失败: ${xhr.responseText}`))
}
} else {
console.error("七牛云上传失败:", xhr.status, xhr.statusText, xhr.responseText)
reject(new Error(`上传失败: ${xhr.status} ${xhr.statusText}`))
}
})
xhr.addEventListener("error", (e) => {
console.error("上传网络错误:", e)
reject(new Error("网络错误,上传失败"))
})
xhr.addEventListener("abort", () => {
reject(new Error("上传被取消"))
})
xhr.open("POST", "https://up-z2.qiniup.com")
xhr.send(formData)
})
}