Express + Multer, 어렵지 않게 사용하기

2020. 5. 27. 04:27BACKEND/Node

반응형

안녕하세요 ❗️

오늘은 Express 를 사용해서 서버를 구축할 때, 이미지를 다루는 방법에 대해 알아볼 예정입니다.

게시글에 이미지를 첨부하는 서비스나, 프로필 사진 업데이트 기능을 만들고 싶을 때 참고하면 좋겠죠❓ 

코드는 깃 허브에 올려둘테니, 필요하신 분들은 보시면서 읽으면 좋을 것 같아요 〰️

 

 

*****************  INDEX  *****************

 

🚀 multer ❓ 

🎯 Single Image

🖍 Image Array

💼 Image Array - using Field Name

 

******************************************** 

 


 

🚀  Multer ❓ 

Multer는 파일 업로드를 위해 사용되는 multipart/form-data 를 다루기 위한 node.js 의 미들웨어 입니다. 

하나 혹은 그 이상의 파일을 다루기 위한 모듈입니다.

 

Multer는 파일을 받아서 request에 file 혹은 files를 추가하여 넘겨줍니다. 

쉽게 생각할 수 있는 기능이라, 설명은 이쯤해두고 프로젝트를 같이 만들어볼까요❓ 

 

기본 설정

1. express 프로젝트 생성하기

2. multer module 설치하기

3. 프로젝트 구조

 

위와 같은 순서로 기본적인 설정을 해보겠습니다.

 

 

1. Express 프로젝트 생성하기

 

$ express <project-name>
$ cd <project-name>
<project-name>$ npm install

 

 

2. multer module 설치하기

 

npm install --save multer

 

 

3. 프로젝트 구조

 

.
├── app.js
├── bin/
├── controllers/
│   └── userController.js
├── package.json
├── public/
├── routes/
│   ├── index.js
│   └── users.js
└── views/

 

추가된 파일 : controllers/userController.js

 

 

 

🎯  Single Image

 

이제 multer를 직접 다뤄볼까요❓ 

굉장히 간단해서 쉽게 따라하실 수 있을 것 같아요.

 

하나의 이미지를 받고, 프로젝트 내부에 저장해보도록 하겠습니다.

두 단계로 나눠 진행해보도록 하겠습니다.

 

1. routes/users.js

2. controllers/userController.js

 

위와 같이 두 개의 파일을 수정해보도록 해보겠습니다.

 

 

1. routes/users.js

제일 먼저, routes/users.js 에 multer 모듈을 추가해주세요. 

 

 

추가적으로 upload 상수를 선언했습니다.

multer({dest: ... })  를 담았는데, 무슨 의미일까요❓ 

multer 모듈을 사용할 때, 추가할 옵션들을 추가하는 것입니다.

 

가장 기본 옵션인 dest 는 파일을 어디에 저장할 것인지를 설정해주는데요.

위의 코드를 보면  uploads/  폴더에 담는 다고 설정해두었습니다.

만약, 'uploads/' 폴더가 없다면 multer가 자동으로 생성해줍니다.

 

만일 옵션 객체를 생략했다면, 파일은 디스크가 아니라 메모리에 저장합니다.

추가적인 옵션은 아래와 같이 설정하고 있습니다.

 

Key Description
dest or storage 파일이 저장될 위치
fileFilter 어떤 파일을 허용할지 제어하는 함수
limits 업로드 된 데이터의 한도
preservePath 파일의 base name 대신 보존할 파일의 전체 경로

 

 

모듈을 추가했다면, 이제 사용을 해봐야겠죠❓ 

multer에는 세 가지의 메소드가 있는데요.

그 중 하나가 바로 .single(fieldName) 메소드입니다.

 

 

✔️  multer.single(fieldName)


이 메소드는 fieldName으로 명시된 이름의 파일을 전달 받습니다.
이미지를 받아서 req.file에 저장하여 다음(next())으로 넘겨주는 역할을 하죠 〰️ 

 

 

multer.single 미들웨어가 성공적으로 마치고 나면 메인 로직을 진행하기 위해 controller를 연결시켜줍니다.

전체 코드를 보면 아래와 같습니다 〰️ 

 

설정하셨나요  ❓

사실 이렇게 multer 모듈 사용이 끝났어요.

multer의 역할은 파일을 가져와서, request 객체에 file/files 속성을 추가해주어 다음(next())으로 넘겨줍니다.

 

 

 

 

2. controllers/userController.js

 

controller에서는 받은 request 에서 file 정보를 가져와 데이터베이스 작업을 하거나, 특정 로직을 구현하면 되겠죠❓ 

하지만 지금은 간단히 알아보는 시간이기 때문에, 프로젝트 내부에 저장된 이미지 주소를 반환해주도록 하겠습니다.

 

 

위와 같은 코드를 짤 수 있습니다. 코드를 같이 알아볼까요 〰️ 

위에 적힌 util은 조금 이따가 다시 보겠습니다❗️ 

 

먼저 req.file 에 몇 가지 속성을 사용할 수 있습니다.

 

Key Description
fieldname   폼에 정의된 필드 명
originalname   사용자가 업로드한 파일 명
encoding   파일의 엔코딩 타입
mimetype   파일의 Mime 타입
size   파일의 바이트(byte) 사이즈
destination   파일이 저장된 폴더
filename   destination 에 저장된 파일 명
path   업로드된 파일의 전체 경로
buffer   전체 파일의 Buffer

 

위와 같은 속성들을 사용할 수 있습니다.

실제로 이미지가 처리되고 난 후 req.file 을 출력해보면 아래와 같은 객체를 확인할 수 있습니다.

직접 보니, 어떤 내용이 포함되는 지 이해가시나요❓ 

여기까지 잘 따라왔다면, 이제 이미지 받는 기능을 구현 완료한 것에요❗️ 

굉장히 간단하죠 〰️ 

 

코드를 보면 util.fail과 util.success가 사용되었는데, 제가 만든 json response 형식이에요 〰️ 

원래는 module 내부에 정의했지만, 지금은 간단한 튜토리얼이기 때문에 userController 내부에 정의하여 사용하겠습니다.

 

 

 

자, 이제 postman으로 직접 테스트를 해볼게요.

 

위와 같이 테스트를 하면 됩니다 〰️ 

postman 사용법은 포스팅을 해두었으니, 따로 설명을 하지는 않겠습니다 ❗️ 

 

 

🖍  Image Array

이번에는 여러 이미지를 받는 방법을 알아보겠습니다.

single image를 하셨다면 어렵지 않게 구현하실 수 있습니다.

이 것도 두 단계로 나눠 진행해보도록 하겠습니다.

 

1. routes/users.js

2. controllers/userController.js

 

위와 같이 두 개의 파일을 수정해보도록 해보겠습니다.

 

1. routes/users.js

이번에는 여러 장의 selfie를 받는 기능을 해볼게요 〰️ 

 

 

10번째 줄을 추가해주시면 됩니다 ❗️ 

upload.array() 라는 메소드를 사용했는데요.

 

 

✔️  multer.array(fieldName [, maxCount] )

.array(fieldName[, maxCount])   는 fieldname 인자에 명시된 이름의 파일 전부를 배열 형태로 전달 받습니다.

선택적으로 maxCount 보다 많은 이미지를 업로드할 경우 에러가 나게 됩니다.

.array 메소드는 req.file이 아닌 req.files에 배열의 형식으로 저장됩니다. 

 

 

위의 코드를 예시로 보면, 'image'라는 필드 이름을 가진 이미지들을 최대 4개까지 받은 다음 UserController에 정의되어있는 uploadImages 의 실행을 시키게끔 합니다.

 

 

 

2. controllers/userController.js 

 

그럼 이 번엔 UserController에 있는 uploadImages 메소드를 생성시켜볼까요❓

 

 

구현하면 위와 같은 모습을 보여주게 됩니다.

이미지 배열 객체를 받고, 이미지 저장 배열을 따로 만들어서 response로 반환하게 됩니다. 

 

구현이 되었다면, 이제 postman으로 테스트 한 번 해볼까요❓ 

 

위와 같이 테스트를 마치면 성공 〰️ 

이미지를 여러개 선택하는  방법은 Shift를 누르시거나, 드래그할 때 여러개를 누르시면 됩니다❗️ 

 

 

 

게시글이 꽤 길어져서 여러 이미지를 다른 filed name으로 받는 방법에 대해 소개해드리는 것까지는 힘들 것 같네요 🤣

다음에 시간이 된다면, 꼭 한 번 다루겠습니다 〰️ 
[2022.05.23  추가]

 

🤖 Multi Fields

글을 작성하고 한참 후에 멀티 필드를 다루네요 ㅎㅎ

사실, 깃허브를 보시면 멀티 필드에 대한 코드가 이미 있습니다.

제가 이 글을 작성할 당시 너무 힘들어서 ~.~ ㅎㅎ

댓글로 의견 주셔서 이 기회에 추가 하겠습니다.

 

 

1. routes/user.js

 

background와 profiles라는 두 필드를 각각 받는 방법입니다.

 

const express = require('express');
const router = express.Router();
const UserController = require('../controllers/user');
const multer = require('multer');
const upload = multer({
  dest: 'uploads/'
});
const multiImg = upload.fields([{ name: 'background', maxCount: 1 }, { name: 'profiles', maxCount: 3 }]);

router.post('/profile', upload.single('image'), UserController.uploadImage);
router.post('/selfies', upload.array('image', 4), UserController.uploadImages);
router.post('/multi', multiImg, UserController.uploadMultiImages);

module.exports = router;

 

위의 array 처럼 maxCount를 지정해서 요청받는 이미지의 개수를 제한할 수 있습니다.

 

 

2. controllers/user.js

 

const util = require('../modules/util');
const multer = require('multer');

module.exports = {
    uploadImage: async (req, res) => {
    	// ...
    },
    uploadImages : async (req, res) => {
        // ...
    },
    uploadMultiImages: async (req, res) => {
        const image = req.files;
        const backImage = image.background[0];
        const profiles = image.profiles;
        const profilePath = profiles.map(img => img.path);
        if (image === undefined) {
            return res.status(400).send(util.fail(400, "이미지가 존재하지 않습니다."));
        }
        const dto = {
            backImage : backImage.path,
            profiles : profilePath
        }
        res.status(200).send(util.success(200, "요청 성공 〰️ ", dto));
    }
}

 

컨트롤러는 위와 같이 간단하게 구현할 수 있습니다.

 

 

 

 

그럼 이상으로 포스팅을 마치겠습니다 🙌🏻

반응형