React - nodejs Multer를 이용하여 이미지 파일 올리기

mhlog·2023년 4월 29일
0

React

목록 보기
6/10
post-thumbnail

사이드 프로젝트를 진행하던 중 nodejs단 서버로 이미지 파일을 전송하는 기능을 구현해야 했다. 구글링을 통해 찾아보니 multer라는 라이브러리를 이용하여 이미지 파일을 쉽게 주고 받을 수 있다고 한다. multer 라이브러리 사용법에 대해서 자세히 알아보자.

이미지를 관리하는 여러 방법

웹 사이트를 운영하면 이미지를 업로드하고 보여줄 일이 자주 생기게 된다. 이미지를 관리하는 방법에는 크게 3가지가 있다.

  • server단에서 폴더를 하나 만들어서 (보통 public 폴더로 생성)하여 저장하는 방법
  • Amazon 같은곳에서 하드를 구매해서 거기에 저장 (Amazon S3 방식)
  • DB에 직접 저장하는 방식

그런데 DB에 직접 저장하는 방식은 느리고, 비싸기때문에 보통 1번과 2번 방식을 많이 사용한다. 저장할 이미지가 매우 많다면 내 하드에 저장하는 1번 방식은 무리가 있기 때문에 2번 방식을 사용하고 저장할 이미지가 내 하드에서 커버 가능하다면 1번 방식을 사용한다. 그리고 이미지를 누가, 어디에, 어떤 이름으로 업로드 했는지와 같은 메타 정보들을 DB에 저장하는 것이 일종의 웹개발 관습이다.

사이드 프로젝트에서는 1번 방법을 대부분 사용하므로 하드에 저장하는 방식으로 살펴보도록 하겠다.

설치

yarn add multer
npm install multer

우선 multer 라이브러리를 설치하여 준다.

Client 단에서 Server로 이미지 보내기

우선 Client 단에서는 Input 태그 중 type이 file로 이미지를 입력받는다. 여러장 입력하는 것도 가능해야하니 multiple 속성을 켜주고, 이미지의 확장자를 jpg, jpeg, png로 제한한다.

<Label>
        사진 등록
        <Input
          type="file"
          name="imageFile"
          accept="image/jpg, image/jpeg, image/png"
          multiple
          onChange={handleChange}
        />
</Label>

onChange로 이미지가 등록될때마다 state로 관리하였다.

이제 Form이 Submit 되면 server측으로 저장할 이미지를 POST 요청 날려주면 된다. 여기서의 Form은 enctype(보내는 파일의 인코딩형식)이 multiplart/form-data로 적어주어야한다. 이미지 전송시에는 인코딩 형식을 multipart/form-data로 설정해주어야한다. 안적어주면 default값인 application/x-www-form-urlencoded라는 base64 형식으로 인코딩 되어서 전달되게 되는데 용량이 조금 증가한다고 한다. 추가로 multer를 사용할 수 없다! multer를 사용할 것이라면 인코딩 형식을 multipart/form-data로 설정해야한다.

요청 날릴때 data는 FormData로 작성해야 한다.

const formData = new FormData();

...생략 (다른 정보들도 FormData에 담아서 전송)
if(imageFile) {
	for (let i = 0; i < values.imageFile.length; i++) {
          formData.append("files", values.imageFile[i]);
    }
}
axios({
  method: "POST",
  url: POST 요청을 날릴 ServerURL,
  headers: {
     "Content-Type": "multipart/form-data"
  },
  data: formData
 })
   .then((result) => {
     // 성공시 수행할 코드
   })
   .catch((error) => {
     // 실패시 수행할 코드
   })

imageFile이 여러개일 수 있으니 조건문으로 imageFile이 있는지 확인하고 반복문으로 formData에 저장하였다.

Server

multer 기본 설정

다음은 Client단에서 보내온 데이터를 multer를 통해서 서버에서 처리하는 로직이다. 우선 multer를 사용하기 위해서는 다음과 같은 코드를 써줘야한다.

let multer = require('multer');
var storage = multer.diskStorage({
  destination: function (req, file, callback) {
    callback(null, './public/image')
  },
  filename: function (req, file, callback) {
    // 한글 이름으로 된 파일이름이 깨지지 않게 하기 위한 코드
    file.originalname = Buffer.from(file.originalname, 'latin1').toString('utf8')
    let fileName = Date.now() + file.originalname;
    callback(null, fileName)
  }
})
var upload = multer({ storage: storage })
  • diskStorage라는 함수를 쓰면 업로드된 파일을 하드에 저장할 수 있다. memoryStorage라고 쓰면 하드 말고 램에 저장할 수 있다 (휘발성)
  • destination: 업로드된 파일을 하드 어떤 경로로 저장할지 정하는 부분이다.
  • filename: 파일의 이름을 정하는 부분이다. file.originalname이 원본 파일명이라는 뜻이고, 앞에 날짜를 붙이는 등 다양하게 커스텀할 수 있다. 이는 사이트마다 다르게 때문에 입맛에 맞게 설정하면 될것같다.

server API 설정

이제 multer를 사용할 준비가 되었으니 client에서 POST 요청을 날릴때 실행해줄 로직을 다음과 같이 구현하면 된다.

Router.post('/', upload.array("files", 5), (req, res) => {
  try {
    console.log(req.files);
    const insertDoc = {
      filename: [],
      path: [],
      SavedTime: [],
    }
    req.files.map((file, index) => {
      insertDoc.filename[index] = file.filename;
      insertDoc.path[index] = file.path;
      insertDoc.SavedTime[index] = new Date();
    })
    // DB에 저장하는 코드
    collection.insertOne(insertDoc);
    res.status(200).json({ message: "DB insertSuccess !"});
  } catch (error) {
    res.status(500).json(error);
  }
})
  • upload.single은 파일 하나만 받는 것이고, 우리는 여러 이미지를 받아야 하므로 upload.array함수로 첫번째 인자에는 fieldname을 써주고 두번 째 인자에는 최대로 받을 파일의 갯수를 지정해준다.
  • file들에 대한 정보는 req.files에 담아서 온다.

req.files에는 다음과 같은 값들이 담겨져온다. 파일의 경로와 현재시간 저장한 filename을 DB에 저장해주었다.

DB에 잘 저장된 것을 확인할 수 있다.

결론

multer에 대해서 알아보았다. 다음 기회에는 multer로 Amazon S3에 이미지를 저장하는 방법에 대해서 구현해보고 싶다.

0개의 댓글