이 블로그는 광고 클릭 수익으로 운영됩니다!
괜찮으시다면 광고 차단을 풀어주세요 ㅠㅠ

게시글

강좌17 - NodeJS - 10달 전 등록 / 6달 전 수정

multer를 사용해 이미지 업로드하기

폼데이터 처리
조회수:
0
이 블로그는 광고 클릭 수익으로 운영됩니다!
괜찮으시다면 광고 차단을 풀어주세요 ㅠㅠ
이 블로그는 광고 클릭 수익으로 운영됩니다!
괜찮으시다면 광고 차단을 풀어주세요 ㅠㅠ

안녕하세요. 이번 시간에는 multer를 사용해 이미지를 업로드 및 폼데이터를 처리하는 것을 알아보겠습니다.

보통 JSON 형식으로 된 데이터는 AJAX로든 폼 태그로든 쉽게 업로드할 수 있습니다. 하지만 이미지 파일만큼은 사람들의 골치를 썩이는데요. express와 함께 사용하면 쉽게 이미지 업로드를 도와주는 multer 모듈이 있습니다.

npm i -S multer

이제 설치된 multer를 사용해 코딩을 해봅시다. 익스프레스 라우터 부분에 다음을 추가해줍니다.

const multer = require('multer');
// 기타 express 코드
const upload = multer({ dest: 'uploads/', limits: { fileSize: 5 * 1024 * 1024 } });
app.post('/up', upload.single('img'), (req, res) => {
  console.log(req.file); 
});

이제 폼데이터나 폼 태그를 통해 업로드한 이미지를 올리면 req.file로 정보가 들어오고, dest 속성에 지정해둔 경로에 이미지가 저장됩니다. limits 속성은 선택 사항인데 여러 가지 제한을 걸 수 있습니다. 위에서는 파일 사이즈를 5MB로 제한했습니다. 폼데이터로 업로드하는 강좌는 여기를 참고하세요. upload.single('img') 미들웨어를 라우터 콜백함수 전에 끼워넣었는데요. 폼데이터의 속성명이 img이거나 폼 태그 인풋의 name이 img인 파일 하나를 받겠다는 뜻입니다. 이미지가 아닌 나머지 데이터는 그대로 req.body에 들어옵니다.

만약 이미지를 하나가 아닌 여러 개를 받고 싶다 하면 upload.array('키', 최대파일개수) 하면 됩니다. req.file 대신 req.files에 정보가 담깁니다.

app.post('/up', upload.array('img'), (req, res) => {
  console.log(req.files);
});

만약 여러 개의 키로 이미지를 올렸다면 upload.fields를 써야 합니다. 사용한 키들을 배열 안에 넣어주면 됩니다.

app.post('/up', upload.fields([{ name: 'img' }, { name: 'photos' }]), (req, res) => {
  console.log(req.files);
});

문제는 uploads 폴더에 뭔가 생성이 되긴 하는데 이름도 ce243370b74107493fea0743d249a176처럼 이상하게 바뀌어있고 확장자도 붙어 있지 않아 쓸 수가 없습니다. 사실 이것은 보안상 의도된 것이지만 지금은 불편하기 때문에 이름이 원래대로 나오게 해보겠습니다. dest 속성 대신 storage 속성을 사용해 upload 변수에 넣어주면 됩니다.

const upload = multer({
  storage: multer.diskStorage({
    destination: function (req, file, cb) {
      cb(null, 'uploads/');
    },
    filename: function (req, file, cb) {
      cb(null, file.originalname);
    }
  }),
});

네. 조금 복잡해졌긴 하지만 위의 코드를 보시면 저장될 경로(destination)과 파일명(filename)을 조작하고 있음을 알 수 있습니다. 이제 다시 파일을 올리면 원본 파일명 그대로 올라갑니다. 그런데 파일명이 중복되는 경우 문제가 생길 수 있죠. 파일명을 타임스탬프로 해서 중복되지 않게 해봅시다.

const path = require('path');
const upload = multer({
  storage: multer.diskStorage({
    destination: function (req, file, cb) {
      cb(null, 'uploads/');
    },
    filename: function (req, file, cb) {
      cb(null, new Date().valueOf() + path.extname(file.originalname));
    }
  }),
});

위와 같이 하시면 타임스탬프.확장자 형식으로 파일명이 지정됩니다.

지금까지는 실제 디스크에 파일을 업로드했는데요. S3같은 곳에 업로드하시는 분들도 있을 겁니다. S3에 업로드하는 방식은 크게 두 가지가 있는데요. 디스크에 있는 파일을 업로드하거나, 파일 버퍼(메모리에 저장)를 업로드하는 겁니다. 파일을 S3에 업로드한 후에는 남아있는 파일을 지워줘야 하는데 이게 번거롭죠. 그래서 처음부터 메모리에 파일을 버퍼 형식으로 저장하고, 그것을 업로드하는 겁니다.

const upload = multer({
  storage: multer.memoryStorage(),
});

이 경우는 req.file이나 req.files 안의 파일 데이터에 디스크스토리지일 경우 있었던 destination, filename, path 대신 buffer라는 속성이 새로 생기고 그 값으로 버퍼들이 저장됩니다. 이 버퍼를 사용해서 S3에 버퍼로 업로드하시면 됩니다. 이 방식의 단점은 파일이 여러 개고, 용량이 너무 크면 메모리를 초과해서 서버가 멈춰버릴 수도 있습니다. 보통은 그럴 일은 없겠지만 그럴 수도 있다는 것을 알아두세요.

투표로 게시글에 관해 피드백을 해주시면 많은 도움이 됩니다. 오류가 있다면 어떤 부분에 오류가 있는지도 알려주세요! 잘못된 정보가 퍼져나가지 않도록 도와주세요.
Copyright © 2016- 무단 전재 및 재배포 금지

댓글

3개의 댓글이 있습니다.
한 달 전
게시판과 같은 것을 만들 때는 파일을 업로드하지 않고, 어떤 방법을 쓰나요? 데이터베이스를 쓰나요, 아니면 그냥 파일을 쓰나요?
한 달 전
디비보다는 파일을 씁니다. 하지만 파일을 서버에 저장하기 보다는 cdn에 저장하곤 합니다.
3달 전
안녕하세요^^ 혹시 파일업로드 관련해서 혹시 도움 좀 주실 수 있을까요?
3달 전
multer 사용하시나요?
3달 전
그건 아닌데 폼 방식이 multipart/form-data 여서요~
3달 전
어떤 부분이 궁금하신가요??
3달 전
내용이 조금 있어서 혹시 메신저나 이메일 주소 등의 연락방법이 있을가요^^?
3달 전
옆의 페북 메신저 사용하시거나 알림 메일가는 주소로 연락주시면 됩니다.
4달 전
안녕하세요. 글 잘 읽어봤는데요. 한가지 궁금한 점이 있는데 이 게시글에서는 multer 모듈을 사용해서 이미지를 파일로 저장하셨는데 찾아보니까 몽고 디비를 이용해서 저장을 하는것도 있더라구요. (https://medium.com/@alvenw/how-to-store-images-to-mongodb-with-node-js-fb3905c37e6d) 속도나 효율 등의 면에서 보통 어떤 방식이 주로 사용되는지 알 수 있을까요? 그리고 'S3같은 곳에 업로드하시는 분들도 있을 겁니다' 에서 S3가 뭔가요?
3달 전
S3는 아마존의 파일 스토리지입니다. 파일로 저장하는 것이 몽고디비 gridfs 등을 사용하는 것보다 편리합니다.