fix: Prevent concurrent upload conflicts with unique file names

- Add generateUniqueFileName function using crypto.randomBytes
- Replace Date.now() with timestamp + random hex for all file names
- Ensures unique file names even when multiple users upload simultaneously
- Fixes: temp PSD files, temp preview files, S3 preview files, and material files
- Resolves reported issue of upload errors with concurrent users
This commit is contained in:
chenpei 2025-10-26 17:21:39 +08:00
parent 765bdef97c
commit 030fb2af0b

View File

@ -7,6 +7,14 @@ import { processImage, getProcessedFileName } from '@/lib/image-processor'
import { generatePsdPreview, hasPsdExtension } from '@/lib/psd-processor'
import { writeFile, mkdir, unlink } from 'fs/promises'
import path from 'path'
import { randomBytes } from 'crypto'
// 生成唯一文件名(避免并发冲突)
function generateUniqueFileName(prefix: string, ext: string): string {
const timestamp = Date.now()
const randomId = randomBytes(8).toString('hex') // 16个字符的随机字符串
return `${prefix}-${timestamp}-${randomId}${ext}`
}
// Configure route to handle large files
export const runtime = 'nodejs'
@ -105,14 +113,14 @@ export async function POST(req: NextRequest) {
const uploadDir = process.env.UPLOAD_DIR || './uploads'
await mkdir(uploadDir, { recursive: true })
const tempPsdFileName = `temp-psd-${Date.now()}-${zipFile.name}`
const tempPsdFileName = generateUniqueFileName('temp-psd', `.${zipFile.name.split('.').pop()}`)
const tempPsdPath = path.join(uploadDir, tempPsdFileName)
const psdBuffer = Buffer.from(await zipFile.arrayBuffer())
await writeFile(tempPsdPath, psdBuffer)
console.log('[Upload] Temporary PSD saved:', tempPsdPath)
// Generate preview image
const tempPreviewPath = path.join(uploadDir, `temp-preview-${Date.now()}.jpg`)
const tempPreviewPath = path.join(uploadDir, generateUniqueFileName('temp-preview', '.jpg'))
const result = await generatePsdPreview(tempPsdPath, tempPreviewPath, 800)
if (!result.success || !result.previewPath) {
@ -147,7 +155,7 @@ export async function POST(req: NextRequest) {
console.log('[Upload] Temporary files cleaned up')
// Upload to S3
previewFileName = `preview-${Date.now()}-generated.webp`
previewFileName = generateUniqueFileName('preview', '-generated.webp')
previewUrl = await uploadToS3(processedBuffer, previewFileName, 'image/webp')
console.log('[Upload] Auto-generated preview uploaded to S3:', previewUrl)
@ -209,7 +217,8 @@ export async function POST(req: NextRequest) {
// Upload processed preview image to S3
console.log('[Upload] Uploading image to S3...')
const processedFileName = getProcessedFileName(previewImage.name)
previewFileName = `preview-${Date.now()}-${processedFileName}`
const fileExt = path.extname(processedFileName)
previewFileName = generateUniqueFileName('preview', fileExt)
previewUrl = await uploadToS3(processedBuffer, previewFileName, 'image/webp')
console.log('[Upload] Image uploaded to S3:', previewUrl)
}
@ -219,7 +228,8 @@ export async function POST(req: NextRequest) {
const uploadDir = process.env.UPLOAD_DIR || './uploads'
await mkdir(uploadDir, { recursive: true })
const zipFileName = `zip-${Date.now()}-${zipFile.name}`
const zipFileExt = path.extname(zipFile.name)
const zipFileName = generateUniqueFileName('material', zipFileExt)
const zipFilePath = path.join(uploadDir, zipFileName)
// If it's a PSD file, we already have the buffer from above