87 lines
3.1 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 { NextRequest, NextResponse } from 'next/server';
import { getServerSession } from 'next-auth';
import { authOptions } from '@/lib/auth';
import { prisma } from '@/lib/prisma';
import { uploadToS3 } from '@/lib/s3';
import { normalizeUrl } from '@/lib/utils';
import { compressImage, sanitizeFileName } from '@/lib/image-processor';
import path from 'path';
// POST /api/user/avatar - 上传用户头像
export async function POST(request: NextRequest) {
try {
const session = await getServerSession(authOptions);
const userId = session?.user ? (session.user as any).id : undefined;
console.log('[UserAvatar] Session:', { userId, hasSession: !!session, hasUser: !!session?.user });
if (!userId) {
console.log('[UserAvatar] No user ID in session');
return NextResponse.json({ error: '未登录' }, { status: 401 });
}
const formData = await request.formData();
const avatar = formData.get('avatar') as File | null;
if (!avatar) {
console.log('[UserAvatar] No avatar file provided');
return NextResponse.json({ error: '请选择头像文件' }, { status: 400 });
}
console.log('[UserAvatar] File info:', { name: avatar.name, type: avatar.type, size: avatar.size });
// 验证文件类型
if (!['image/jpeg', 'image/jpg', 'image/png', 'image/webp'].includes(avatar.type)) {
return NextResponse.json(
{ error: '不支持的图片格式,请使用 JPG、PNG 或 WebP 格式' },
{ status: 400 }
);
}
// 验证文件大小(5MB)
if (avatar.size > 5 * 1024 * 1024) {
return NextResponse.json(
{ error: `头像过大,请使用小于5MB的图片(当前:${(avatar.size / 1024 / 1024).toFixed(2)}MB)` },
{ status: 400 }
);
}
// 压缩图片
const imageBuffer = Buffer.from(await avatar.arrayBuffer());
const compressedBuffer = await compressImage(imageBuffer, {
maxSizeKB: 100,
maxWidth: 200,
maxHeight: 200,
format: 'webp',
});
// 上传到S3
const sanitizedName = sanitizeFileName(avatar.name);
const ext = path.extname(sanitizedName) || '.webp';
const fileName = `avatar-${userId}-${Date.now()}${ext}`;
console.log('[UserAvatar] Uploading to S3:', fileName, `(${(compressedBuffer.length / 1024).toFixed(2)}KB)`);
const avatarUrl = await uploadToS3(compressedBuffer, fileName, 'image/webp');
console.log('[UserAvatar] S3 URL:', avatarUrl);
// 更新用户头像
console.log('[UserAvatar] Updating user:', userId);
const updatedUser = await prisma.user.update({
where: { id: userId },
data: { avatar: avatarUrl },
});
console.log('[UserAvatar] User updated:', { id: updatedUser.id, avatar: updatedUser.avatar });
// 规范化URL
const normalizedUrl = normalizeUrl(avatarUrl);
return NextResponse.json({ avatarUrl: normalizedUrl });
} catch (error) {
console.error('[UserAvatar] POST error:', error);
return NextResponse.json({ error: '上传头像失败' }, { status: 500 });
}
}