87 lines
2.4 KiB
TypeScript
87 lines
2.4 KiB
TypeScript
/**
|
||
* 用户头像上传API
|
||
*
|
||
* POST: 上传用户头像
|
||
*
|
||
* @created 2025-11-25
|
||
* @api
|
||
*/
|
||
|
||
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 { processImage, getProcessedFileName } from '@/lib/image-processor'
|
||
import path from 'path'
|
||
|
||
export async function POST(req: NextRequest) {
|
||
try {
|
||
const session = await getServerSession(authOptions)
|
||
if (!session?.user?.id) {
|
||
return NextResponse.json(
|
||
{ error: '未登录' },
|
||
{ status: 401 }
|
||
)
|
||
}
|
||
|
||
const formData = await req.formData()
|
||
const avatarFile = formData.get('avatar') as File
|
||
|
||
if (!avatarFile) {
|
||
return NextResponse.json(
|
||
{ error: '请选择头像文件' },
|
||
{ status: 400 }
|
||
)
|
||
}
|
||
|
||
// 验证文件类型
|
||
const allowedImageTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp']
|
||
if (!allowedImageTypes.includes(avatarFile.type)) {
|
||
return NextResponse.json(
|
||
{ error: '不支持的图片格式,请使用 JPG、PNG 或 WebP 格式' },
|
||
{ status: 400 }
|
||
)
|
||
}
|
||
|
||
// 验证文件大小(限制5MB)
|
||
const maxSize = 5 * 1024 * 1024 // 5MB
|
||
if (avatarFile.size > maxSize) {
|
||
return NextResponse.json(
|
||
{ error: `头像过大,请使用小于5MB的图片(当前:${(avatarFile.size / 1024 / 1024).toFixed(2)}MB)` },
|
||
{ status: 400 }
|
||
)
|
||
}
|
||
|
||
// 处理头像:压缩并转换为webP
|
||
const originalBuffer = Buffer.from(await avatarFile.arrayBuffer())
|
||
const processedBuffer = await processImage(originalBuffer, {
|
||
maxSizeKB: 200,
|
||
maxWidth: 400,
|
||
maxHeight: 400,
|
||
format: 'webp',
|
||
})
|
||
|
||
// 上传到S3
|
||
const processedFileName = getProcessedFileName(avatarFile.name)
|
||
const fileExt = path.extname(processedFileName)
|
||
const avatarFileName = `avatar-${session.user.id}-${Date.now()}${fileExt}`
|
||
const avatarUrl = await uploadToS3(processedBuffer, avatarFileName, 'image/webp')
|
||
|
||
// 更新数据库
|
||
await prisma.user.update({
|
||
where: { id: session.user.id },
|
||
data: { avatar: avatarUrl },
|
||
})
|
||
|
||
return NextResponse.json({ avatarUrl })
|
||
} catch (error) {
|
||
console.error('[UserAvatar] POST error:', error)
|
||
return NextResponse.json(
|
||
{ error: '上传头像失败' },
|
||
{ status: 500 }
|
||
)
|
||
}
|
||
}
|
||
|