2025-12-17 20:15:18 +08:00

94 lines
3.0 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 { NextResponse } from "next/server";
import { z } from "zod";
import { auth } from "@/app/(auth)/auth";
import { uploadFile } from "@/lib/storage/service";
// Use Blob instead of File since File is not available in Node.js environment
const FileSchema = z.object({
file: z
.instanceof(Blob)
.refine((file) => file.size <= 8 * 1024 * 1024, {
message: "File size should be less than 8MB",
})
// Update the file type based on the kind of files you want to accept
.refine((file) => ["image/jpeg", "image/png", "image/webp"].includes(file.type), {
message: "File type should be JPEG, PNG or WebP",
}),
});
export async function POST(request: Request) {
console.log("[Upload API] Received upload request");
const session = await auth();
if (!session) {
console.log("[Upload API] Unauthorized - no session");
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
if (request.body === null) {
console.log("[Upload API] Request body is empty");
return new Response("Request body is empty", { status: 400 });
}
try {
const formData = await request.formData();
const file = formData.get("file") as Blob;
console.log("[Upload API] FormData received, file exists:", !!file);
if (!file) {
console.log("[Upload API] No file in FormData");
return NextResponse.json({ error: "No file uploaded" }, { status: 400 });
}
console.log("[Upload API] File info:", {
type: file.type,
size: file.size,
sizeInMB: (file.size / 1024 / 1024).toFixed(2) + "MB"
});
const validatedFile = FileSchema.safeParse({ file });
if (!validatedFile.success) {
const errorMessage = validatedFile.error.errors
.map((error) => error.message)
.join(", ");
console.log("[Upload API] Validation failed:", errorMessage);
return NextResponse.json({ error: errorMessage }, { status: 400 });
}
// Get filename from formData since Blob doesn't have name property
const filename = (formData.get("file") as File).name;
console.log("[Upload API] Filename:", filename);
const fileBuffer = await file.arrayBuffer();
console.log("[Upload API] File buffer size:", fileBuffer.byteLength);
try {
// 使用统一的存储服务(支持数据库配置的 S3、环境变量 S3 或 Vercel Blob)
const data = await uploadFile(filename, fileBuffer);
console.log("[Upload API] Upload successful:", data.url);
return NextResponse.json(data);
} catch (_error) {
console.error("[Upload API] Upload failed:", _error);
return NextResponse.json({
error: "Upload failed",
details: _error instanceof Error ? _error.message : String(_error)
}, { status: 500 });
}
} catch (_error) {
console.error("[Upload API] Request processing failed:", _error);
return NextResponse.json(
{
error: "Failed to process request",
details: _error instanceof Error ? _error.message : String(_error)
},
{ status: 500 }
);
}
}