Files
MemeStudio/lib/cos-client.ts
2026-05-01 08:44:56 +08:00

82 lines
2.2 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 COS from 'cos-js-sdk-v5'
import { apiFetch } from '@/lib/api'
interface TempKeyResponse {
credentials: {
tmpSecretId: string
tmpSecretKey: string
sessionToken: string
}
startTime: number
expiredTime: number
bucket: string
region: string
}
let cachedKey: TempKeyResponse | null = null
async function getTempKey(forceRefresh = false): Promise<TempKeyResponse> {
const now = Math.floor(Date.now() / 1000)
// 提前 60 秒失效,避免边界问题
if (!forceRefresh && cachedKey && cachedKey.expiredTime - 60 > now) {
return cachedKey
}
const res = await apiFetch('/api/cos/temp-key')
if (!res.ok) {
throw new Error('获取上传凭证失败')
}
const data = (await res.json()) as TempKeyResponse
cachedKey = data
return data
}
function buildCosClient(key: TempKeyResponse): COS {
return new COS({
getAuthorization: (_options, callback) => {
callback({
TmpSecretId: key.credentials.tmpSecretId,
TmpSecretKey: key.credentials.tmpSecretKey,
SecurityToken: key.credentials.sessionToken,
StartTime: key.startTime,
ExpiredTime: key.expiredTime,
})
},
})
}
function randomFilename(originalName: string): string {
const ext = originalName.split('.').pop() || 'jpg'
const timestamp = Date.now()
const randomStr = Math.random().toString(36).substring(2, 8)
return `mini_game/images/${timestamp}_${randomStr}.${ext}`
}
/**
* 上传单个文件到腾讯云 COS返回可访问的 URL。
*/
export async function uploadToCos(file: File | Blob, originalName?: string): Promise<string> {
const name = originalName || (file as File).name || 'upload.jpg'
const key = await getTempKey()
const cos = buildCosClient(key)
const filename = randomFilename(name)
return new Promise<string>((resolve, reject) => {
cos.putObject(
{
Bucket: key.bucket,
Region: key.region,
Key: filename,
Body: file as File,
},
(err) => {
if (err) {
reject(new Error(err.message || '上传失败'))
return
}
const url = `https://${key.bucket}.cos.${key.region}.myqcloud.com/${filename}`
resolve(url)
}
)
})
}