/** * 图片上传API * 支持上传图片到public/assets目录 */ import { NextRequest, NextResponse } from 'next/server' import { writeFile, mkdir } from 'fs/promises' import { existsSync } from 'fs' import path from 'path' // 支持的图片格式 const ALLOWED_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/svg+xml'] const MAX_SIZE = 5 * 1024 * 1024 // 5MB /** * POST - 上传图片 */ export async function POST(request: NextRequest) { try { const formData = await request.formData() const file = formData.get('file') as File | null const folder = formData.get('folder') as string || 'uploads' if (!file) { return NextResponse.json({ success: false, error: '请选择要上传的文件' }, { status: 400 }) } // 验证文件类型 if (!ALLOWED_TYPES.includes(file.type)) { return NextResponse.json({ success: false, error: '不支持的文件格式,仅支持 JPG、PNG、GIF、WebP、SVG' }, { status: 400 }) } // 验证文件大小 if (file.size > MAX_SIZE) { return NextResponse.json({ success: false, error: '文件大小不能超过5MB' }, { status: 400 }) } // 生成唯一文件名 const timestamp = Date.now() const randomStr = Math.random().toString(36).substring(2, 8) const ext = file.name.split('.').pop() || 'jpg' const fileName = `${timestamp}_${randomStr}.${ext}` // 确保上传目录存在 const uploadDir = path.join(process.cwd(), 'public', 'assets', folder) if (!existsSync(uploadDir)) { await mkdir(uploadDir, { recursive: true }) } // 写入文件 const filePath = path.join(uploadDir, fileName) const bytes = await file.arrayBuffer() const buffer = Buffer.from(bytes) await writeFile(filePath, buffer) // 返回可访问的URL const url = `/assets/${folder}/${fileName}` return NextResponse.json({ success: true, data: { url, fileName, size: file.size, type: file.type } }) } catch (error) { console.error('[Upload API] 上传失败:', error) return NextResponse.json({ success: false, error: '上传失败: ' + (error as Error).message }, { status: 500 }) } } /** * DELETE - 删除图片 */ export async function DELETE(request: NextRequest) { try { const { searchParams } = new URL(request.url) const filePath = searchParams.get('path') if (!filePath) { return NextResponse.json({ success: false, error: '请指定要删除的文件路径' }, { status: 400 }) } // 安全检查:确保只能删除assets目录下的文件 if (!filePath.startsWith('/assets/')) { return NextResponse.json({ success: false, error: '无权限删除此文件' }, { status: 403 }) } const fullPath = path.join(process.cwd(), 'public', filePath) if (!existsSync(fullPath)) { return NextResponse.json({ success: false, error: '文件不存在' }, { status: 404 }) } const { unlink } = await import('fs/promises') await unlink(fullPath) return NextResponse.json({ success: true, message: '文件删除成功' }) } catch (error) { console.error('[Upload API] 删除失败:', error) return NextResponse.json({ success: false, error: '删除失败: ' + (error as Error).message }, { status: 500 }) } }