Files
waooplus/scripts/test-image-url-flow.ts
2026-03-08 17:10:06 +08:00

126 lines
4.4 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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.
/**
* 图片 URL 流程测试
* 模拟图片生成后的存储和读取流程
* 运行: npx tsx scripts/test-image-url-flow.ts
*/
import { config } from 'dotenv'
config()
import { uploadObject, getSignedUrl, extractStorageKey, toFetchableUrl } from '../src/lib/storage'
import { keyToSignedUrl, addSignedUrlToLocation } from '../src/lib/storage'
import { encodeImageUrls, decodeImageUrlsFromDb } from '../src/lib/contracts/image-urls-contract'
import { randomUUID } from 'crypto'
async function testImageUrlFlow() {
console.log('🧪 测试图片 URL 全流程...\n')
// 1. 模拟上传图片到存储
console.log('1⃣ 模拟上传图片:')
const testKey = `images/location-${randomUUID()}.jpg`
const testImageContent = Buffer.from('fake-image-data')
let storedKey: string
try {
storedKey = await uploadObject(testImageContent, testKey)
console.log(` ✅ 上传成功,返回 key: ${storedKey}`)
} catch (error) {
console.log(` ❌ 上传失败:`, error)
process.exit(1)
}
// 2. 模拟存储到数据库encodeImageUrls
console.log('\n2⃣ 模拟数据库存储encodeImageUrls:')
const imageUrlsArray = [storedKey]
const dbValue = encodeImageUrls(imageUrlsArray)
console.log(` ✅ 数据库值: ${dbValue}`)
// 3. 模拟从数据库读取decodeImageUrlsFromDb
console.log('\n3⃣ 模拟数据库读取decodeImageUrlsFromDb:')
const decodedKeys = decodeImageUrlsFromDb(dbValue)
console.log(` ✅ 解析出的 keys: ${JSON.stringify(decodedKeys)}`)
// 4. 测试 keyToSignedUrl用于 API 返回给前端)
console.log('\n4⃣ 测试 keyToSignedUrlAPI 层转换):')
for (const key of decodedKeys) {
const signedUrl = keyToSignedUrl(key)
console.log(` Key: ${key}`)
console.log(` → Signed URL: ${signedUrl}`)
// 检查是否是 /api/storage/sign 格式
if (signedUrl?.startsWith('/api/storage/sign')) {
console.log(` ✅ 正确生成了签名 URL 路径`)
} else if (signedUrl?.startsWith('http')) {
console.log(` ⚠️ 返回了完整 HTTP URL可能无法直接访问`)
} else {
console.log(` ⚠️ URL 格式: ${signedUrl}`)
}
}
// 5. 测试 addSignedUrlToLocation完整对象转换
console.log('\n5⃣ 测试 addSignedUrlToLocation完整对象转换:')
const mockLocationFromDb = {
id: 'loc-123',
name: '测试场景',
images: [
{
id: 'img-1',
imageUrl: storedKey,
imageIndex: 0,
}
]
}
const locationWithSignedUrls = addSignedUrlToLocation(mockLocationFromDb)
console.log(` 转换后的 location.images:`)
for (const img of locationWithSignedUrls.images || []) {
console.log(` - imageIndex: ${img.imageIndex}`)
console.log(` - imageUrl: ${img.imageUrl}`)
if (img.imageUrl?.startsWith('/api/storage/sign')) {
console.log(` ✅ 正确: 是相对路径签名 URL`)
} else if (img.imageUrl?.startsWith('http://127.0.0.1:19000')) {
console.log(` ❌ 错误: 是 MinIO 直链,可能需要签名`)
} else if (img.imageUrl?.startsWith('http')) {
console.log(` ⚠️ 是外部 HTTP URL`)
} else {
console.log(` ⚠️ 其他格式: ${img.imageUrl}`)
}
}
// 6. 测试 getSignedUrl 直接调用
console.log('\n6⃣ 测试 getSignedUrl 直接调用:')
const directSignedUrl = getSignedUrl(storedKey)
console.log(` Key: ${storedKey}`)
console.log(` → URL: ${directSignedUrl}`)
// 7. 测试 extractStorageKey
console.log('\n7⃣ 测试 extractStorageKey从各种 URL 提取 key:')
const testUrls = [
storedKey,
`http://127.0.0.1:19000/waoowaoo/${storedKey}`,
directSignedUrl,
]
for (const url of testUrls) {
const extracted = extractStorageKey(url)
console.log(` ${url.substring(0, 60)}...`)
console.log(` → extracted: ${extracted}`)
}
// 8. 清理测试数据
console.log('\n8⃣ 清理测试数据:')
try {
const { deleteObject } = await import('../src/lib/storage')
await deleteObject(storedKey)
console.log(` ✅ 删除成功`)
} catch (error) {
console.log(` ⚠️ 删除失败(可忽略):`, error)
}
console.log('\n✨ 测试完成!')
console.log('\n📋 总结:')
console.log(' 如果第4、5步返回的是 /api/storage/sign?key=... 格式 → ✅ 正常')
console.log(' 如果第4、5步返回的是 http://127.0.0.1:19000/... 格式 → ❌ 需要修复')
}
testImageUrlFlow().catch(console.error)