multer는 파일 업로드에 사용되는 node.js 미들웨어로 멀티파트(multipart/form-data) 형식으로 이루어져 있다
멀티파트는 데이터 요청 시 쓰이는 Content-Type의 한 종류로 multer에서 사용된다
쉽게 말해 이미지,영상,pdf 등 파일형식들을 보낼 때 multer를 사용한다고 보면 된다!
1.설치 방법과 import
npm i multer
const multer = require("multer");
const upload = multer({ dest: "uploads/" });
express 설치해준다음에 해당 npm을 입력해 주면 설치하고 불러와주면 됩니다
2.upload.single()
const express = require('express')
const app = express()
const port = 3000
const multer = require('multer')
const path = require('path')
const upload = multer({ dest: 'uploads/' }) //서비 실행하면 자동으로 폴더를 만들어줌
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'index.html'))
})
app.post('/api/upload', upload.single('avatar'), function (req, res, next) {
})
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})
index.html을 뛰워주고 /api/upload 주소에 post방식으로 요청받는 부분에 upload.single을 작성해 줍니다
upload.single안에 인자값이 여기서 중요한데 인자값에 있는 게 중요합니다
<form method="post" enctype="multipart/form-data" action="/api/upload">
<input type="file" name="avatar" />
<button type="submit">Upload</button>
</form>
upload.single안에 값인 avatar와 프론트에서 input태그 name이랑 동일해야 됩니다
즉 필드명을 기준으로 미들웨어가 확인합니다
{
fieldname: 'avatar',
originalname: 'ChatGPT Image 2025ë\x85\x84 8ì\x9B\x94 24ì\x9D¼ ì\x98¤í\x9B\x84 08_32_30.png',
encoding: '7bit',
mimetype: 'image/png',
destination: 'uploads/',
filename: '1c7478270e7af7e95d5f2cadba0bc6a5',
path: 'uploads\\1c7478270e7af7e95d5f2cadba0bc6a5',
size: 1808556
}
서버에서 console.log(req.file); 을 통해 위와 같이 요청받은 정보를 확인할 수 있습니다
다만 업로드하고 난 뒤 express에서 uploads파일 밑에 저장하지만 multer 기본 모드(dest)는 확장자가 사라진 형태와 랜덤 한 파일명으로 저장된다. 서버 보안상에 이유로 확장자형태로 저장하면 안 된다고 한다. (다만 확장자를 바꾸면 png로 뜨는 걸 확인가능하다)
3.multer.diskStorage()
multer.diskStorage는 프론트에서 업로드받은 파일을 저장위치, 파일이름, 파일확장자등 커스텀하여 직접 제어하기 위해 사용하며
실제 운영 중인 서비스에서도 multer.diskStorage를 통해 관리하면 된다
const express = require('express')
const app = express()
const port = 3000
const multer = require('multer')
const path = require('path');
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, path.join(__dirname, 'uploads')) //저장할경로
},
filename: function (req, file, cb) {
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9)
//날짜와 랜덤함수를 통해 저장
console.log("멀터:",file)
cb(null, file.fieldname + '-' + uniqueSuffix) //파일명 랜덤하게 저장
//두번째 인자값에 file.originalname을 적으면 업로드한 파일명,확장자명 그대로 저장된다
}
})
const upload = multer({ storage })
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'index.html'));
})
app.post('/api/upload', upload.single('avatar'), (req,res)=>{
res.json(req.file)
})
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})
해당 코드를 보면 upload.single에 적은 avatar와 변수 uniqueSuffix를 통해 업로드된 파일 이름을 랜덤값으로 바꿔 저장하게 됩니다. 그리고 file.originalname 이나 path.extname(file.originalname) 같은 확장자를 붙이지 않았으니 확장자 또한 없는 상태로 저장됩니다 즉 이렇게 저장해야 서버에서 보안과 충돌 방지 측면에서 훨씬 안전 하다고 합니다
multer의 경우 동일한 파일명은 덮어서 저장하기 때문에 이렇게 랜덤 한 값을 입혀 사용해야 합니다.
보통 사용자의 uuid을 통해 파일이 저장된다고 합니다
해당 바꾼 값과 업로드된 파일명과 확장자를 db에 저장하고 요청이 오면 확장자를 붙여서 파일을 전송하면 된다고 합니다
4.db에서 값을 가져와 확장자 붙여서 요청한 값 보내기 예제
-html
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>이미지 출력 예제</title>
</head>
<body>
<h2>서버에서 불러온 이미지</h2>
<button id="loadBtn">이미지 불러오기</button>
<div>
<img id="preview" width="200" alt="서버 이미지 미리보기" />
</div>
<script>
const loadBtn = document.getElementById("loadBtn");
const preview = document.getElementById("preview");
loadBtn.addEventListener("click", async () => {
const res = await fetch("/download");
if (!res.ok) {
alert("이미지를 불러올 수 없습니다.");
return;
}
const blob = await res.blob();
const url = URL.createObjectURL(blob);
// 화면에 이미지 표시
preview.src = url;
});
</script>
</body>
</html>
-express
const express = require("express");
const app = express();
const port = 3000;
const multer = require("multer");
const path = require("path");
// DB 조회 결과 (임의로 정해놓음)
const fileFromDB = {
storageName: "avatar-1756100789227-942650701",
ext: ".png",
originalName: "testimg.png",
mimeType: "image/png",
};
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, path.join(__dirname, "uploads")); //저장할경로
},
filename: function (req, file, cb) {
const uniqueSuffix = Date.now() + "-" + Math.round(Math.random() * 1e9);
//날짜와 랜덤함수를 통해 저장
cb(null, file.fieldname + "-" + uniqueSuffix); //파일명 랜덤하게 저장
//두번째 인자값에 file.originalname을 적으면 업로드한 파일명,확장자명 그대로 저장된다
},
});
const upload = multer({ storage });
app.get("/", (req, res) => {
res.sendFile(path.join(__dirname, "index.html"));
});
app.post("/api/upload", upload.single("avatar"), (req, res) => {
res.json(req.file);
});
//프론트로 뛰우기 위한 코드
app.get("/download", (req, res) => {
const filenameWithExt = fileFromDB.storageName + fileFromDB.ext;
const filePath = path.join(__dirname, "uploads", fileFromDB.storageName);
// fileFromDB에 적어놓은 이미지 정보를 토대로 uploads폴더에서 찾아옴
// 파일 응답 내려줄 때 헤더 설정
res.setHeader("Content-Type", fileFromDB.mimeType);
// 👉 브라우저/클라이언트에게 "이 응답은 어떤 타입이다" 라고 알려줌
// 예) image/png → 브라우저가 이미지를 올바르게 렌더링
res.setHeader(
"Content-Disposition",
`inline; filename="${fileFromDB.originalName}"`
);
// 👉 브라우저에게 "이 응답을 어떻게 처리할지" 정보
// attachment → 다운로드 강제 (저장 대화창 뜸)
// inline → 브라우저에서 바로 열림
// filename → 다운로드 시 보여줄 파일 이름 지정
// 파일 읽어서 확장자 붙인 이름처럼 응답하기
res.download(filePath, filenameWithExt, (err) => {
if (err) {
console.error("다운로드 에러:", err);
res.status(500).send("파일 다운로드 실패");
}
});
});
app.listen(port, () => {
console.log(`Example app listening on port ${port}`);
});
/download에 get요청이오면 저장해 놓은 이미지를 fileFromDB에 있는 정보를 토대로
프론트에서 출력하게 됩니다
5.최근 보안 이슈 문제
multer를 공부하다 보니 최근 2025년 7월에 취약점이 발견되어 보안 릴리즈에 포함되었다고 합니다
과거 버전을 사용하는 곳이 있으면 업데이트해야 될 것 같아 보입니다
- 이슈: 잘못된 요청이 들어왔을 때 예외 처리에 문제가 있어 수정됨
- 심각도 : 높은 수준
- 영향받는 버전: >=1.4.4-lts.1 그리고 <2.0.2
- 해결된 버전: 2.0.2 (이 버전 이상으로 업데이트 필요)
-마무리
주로 express 자주 사용하는데 개인 프로젝트를 하다가 파일을 전송하는 방법이 필요해서 공부하다가 multer를 찾게 되었습니다
해당 npm 라이브러리는 생긴 지 10년이 넘은 라이브러리로 많이들 사용함으로 꼭 알아야 될 것 같습니다
https://san2-dev.tistory.com/15
(2025년) Next.js 15 설치 및 개념 완전 정복
리액트를 공부하다 보면 seo최적화 문제를 한 번쯤 듣게 되거나 경험하게 됩니다(저도 그랬고요)이때 next.js를 사용하면 react hook이라던지 기능들을 사용하면서 해결할 수 있다고 합니다오늘은 nex
san2-dev.tistory.com
'express' 카테고리의 다른 글
nodemon 사용법!(자동으로 서버 재 실행) (0) | 2025.03.25 |
---|---|
[nodejs]dotenv로 환경변수 관리하는 방법 (0) | 2025.01.11 |
express 백엔드 설치방법 (0) | 2025.01.08 |