티스토리 뷰
Next.js에서 파일을 업로드할 때, 기본적으로 요청 크기 제한이 1MB로 설정되어 있어 대용량 파일을 업로드하면 문제가 발생할 수 있습니다.
저도 AWS S3에 이미지를 업로드하는 과정에서 'Body exceeded 1MB limit' 오류를 만났는데요. 🤯 이 문제를 해결하는 방법은 여러 가지가 있습니다.
저는 1) Next.js의 API 요청 크기 제한을 늘리는 방법과 2) Presigned URL을 활용해 S3에 직접 업로드하는 방법을 시도해봤습니다. 각각의 방법을 비교하고, 최종적으로 어떤 방식을 선택했는지 공유해보겠습니다! 🚀
해결방법 1
Nextjs는 기본적으로 !MB의 요청 크기 제한을 가지고 있는데요. 이를 늘리려면 bodyParser 설정을 변경해주면 됩니다.
기존 코드에서 export 위에 옵션 설정을 변경해주면 잘 올라갔습니다.
// ✅ API 요청 크기 제한을 10MB로 증가
export const config = {
api: {
bodyParser: {
sizeLimit: '10mb', // 기본 1MB → 10MB로 증가
},
},
};
import { NextApiRequest, NextApiResponse } from 'next';
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
import withHandler from '@libs/server/withHandler';
import { withApiSession } from '@libs/server/withSession';
const s3Client = new S3Client({
region: process.env.AWS_REGION,
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY as string,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY as string,
},
});
async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method === 'POST') {
try {
const { file, name, type } = req.body; // 클라이언트에서 전송한 파일
const buffer = Buffer.from(file, 'base64'); // base64 문자열을 버퍼로 변환합니다.
const fileName = `${Date.now()}_${name}`;
const Key = `images/${fileName}`;
const uploadParams = {
Bucket: process.env.AWS_BUCKET_NAME,
Key, // 파일명을 고유하게 지정합니다.
Body: buffer,
ContentType: type,
};
const command = new PutObjectCommand(uploadParams);
await s3Client.send(command);
res
.status(200)
.json({ message: 'File uploaded successfully', id: fileName });
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Error uploading file' });
}
} else {
res.status(405).json({ error: 'Method Not Allowed' });
}
}
// ✅ API 요청 크기 제한을 10MB로 증가
export const config = {
api: {
bodyParser: {
sizeLimit: '10mb', // 기본 1MB → 10MB로 증가
},
},
};
export default withApiSession(
withHandler({ methods: ['GET', 'POST'], handler })
);


해결방법 2
S3 업로드 방식을 Presigned URL 방식으로 변경해서 해결할 수도 있습니다.
현재 저는 클라이언트에서 Base64로 변환해서 API로 전송하고, 서버에서 S3에서 업로드하는 구조인데요.
여기서 문제점은 Base64 변환 시 파일 크기가 33% 증가하게 됩니다. 그리고 다시 서버에서 Base64 => Buffer로 변환가정이 필요하게 되고, API 서버에서 큰 파일을 직접 처리하기 때문에 성능이 저하될 수 있습니다.
그래서 Presigned URL을 사용해서 클라이언트에서 직접 업로드하면 API 서버가 큰 파일을 처리할 필요가 없고, AWS S3에 부담을 전가할 수 있기 때문에 더 좋아보였습니다.
서버 코드
presigned 기능을 사용할 땐 아래의 패키지가 추가로 필요했습니다.
@aws-sdk/s3-request-presigner
[](https://www.npmjs.com/package/@aws-sdk/s3-request-presigner) [](https://www.npmjs.com/.
www.npmjs.com
import { NextApiRequest, NextApiResponse } from "next";
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
const s3Client = new S3Client({
region: process.env.AWS_REGION,
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY as string,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY as string,
},
});
async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== "POST") {
return res.status(405).json({ error: "Method Not Allowed" });
}
try {
const { name, type } = req.body;
const fileName = `${Date.now()}_${name}`;
const Key = `images/${fileName}`;
const command = new PutObjectCommand({
Bucket: process.env.AWS_BUCKET_NAME,
Key,
ContentType: type,
});
const signedUrl = await getSignedUrl(s3Client, command, { expiresIn: 60 }); // 60초 동안 유효한 URL
res.status(200).json({ url: signedUrl, fileName });
} catch (err) {
console.error(err);
res.status(500).json({ error: "Error generating signed URL" });
}
}
export default handler;
클라이언트 코드
기존에는 파일 데이터를 넘겼다면 이름과 타입만 넘기고, URL을 받아서 URL로 파일을 패치하도록 했습니다.
export const uploadFile = async (file: File): Promise<string> => {
// 1. 서버에서 Presigned URL 요청
const res = await fetch("/api/files", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
name: file.name,
type: file.type,
}),
});
const { url, fileName } = await res.json();
// 2. Presigned URL을 사용하여 파일을 S3에 직접 업로드
const uploadRes = await fetch(url, {
method: "PUT",
headers: { "Content-Type": file.type },
body: file,
});
if (!uploadRes.ok) {
throw new Error("Upload failed");
}
return fileName; // 성공 시 업로드된 파일명 반환
};

이처럼 파일 업로드 방식에는 여러 가지가 있으며, 프로젝트 상황에 맞는 최적의 방법을 선택하는 것이 중요합니다. 저는 결국 Presigned URL 방식을 적용했는데, 서버 부담을 줄이면서도 성능을 최적화할 수 있기 때문입니다.
여러분도 프로젝트 상황에 따라 적절한 방식을 선택하시길 바랍니다! 😀
'배포' 카테고리의 다른 글
AWS S3에 이미지 업로드하기 (Nextjs) (0) | 2025.02.23 |
---|---|
Cloudflare 이미지 업로드, AWS 프리티어로 대체하기 (S3 + CloudFront 활용) (0) | 2025.02.22 |
1년 만에 프로젝트 복원: PlanetScale에서 AWS RDS & EC2로 이전하기 (0) | 2025.02.22 |
vite를 이용해 편하게 npm 패키지 배포하기 (CJS, ESM 모두 사용 가능) (1) | 2023.10.31 |
[ERROR] Netlify 배포 시 node version error 해결 방법 (0) | 2023.01.08 |
- Total
- Today
- Yesterday
- 위코드
- 북클럽
- 프론트앤드
- C언어
- 윤성우 열혈C프로그래밍
- 스토리 북
- 노마드코더
- 원티드
- env
- 노개북
- 초보
- 프리온보딩
- error
- TopLayer
- React
- NextRequest
- NextApiRequest
- WSL2
- CLASS
- nextjs
- 우아한테크코스
- 아차산
- javascript
- createPortal
- jest
- nodejs
- electron
- import/order
- Storybook
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |