본문 바로가기
경일/nodejs

[node.js] multer 이용해서 파일 업로드

by dev_kong 2022. 3. 15.
728x90
728x90

파일업로드

1. 개요

2. FRONT

3. BACK

1. 개요

파일 업로드를 하는 방법을 알아볼거다.
그런데 직접 구현 하는건 거의 불가능에 가까우ㄴ니
외부 라이브러리를 사용하자
사용할 라이브러리의 이름은 multer 이다.

2. FRONT

우선 서버에다 파일을 보낼 HTML을 만들어준다.

     <form method="post" action="/upload" enctype="multipart/form-data">
      <input type="text" name="subject" />
      <input type="file" />
      <button type="submit">전송</button>
    </form>

기본적은 form 태그이다.
그런데 기존에 만들던 form 태그와 다른점은
form 태그의 enctype이란 속성이 들어가있다.

form태그로 전달해줄 Content-type을 지정해주는 역할을 한다.
파일 업로드에 사용되는 Content-type은
multipart/form-data 이다.
(default는 x-www-form-urlencoded 이다)

그리고 한가지 더
input type에 file을 이용해준다.

정말 정말 신기한건 이렇게 이미지를 업로드하면,
이미지파일을 텍스트로 변환해서(!)
텍스트가 업로드 된다.

정확하게는 이미지 파일자체가 텍스트로 이루어져잇고,
우리가 사용하는 os가 이 이미지를 파싱해준다.
업로드하는 행위는 파싱되어있는 이미지파일을 다시 원래의 형태(텍스트)로 변환해서
서버로 전송해주는 것이다.

3. BACK

app.use(express.json());
app.use(express.urlencoded());

위 두개의 라우터는
각각 post요청으로 전달된 json형식의 데이터와
x-www-form-urlencoded 형식의 데이터를 읽고
req.body 라는 객체를 만들어서 데이터를 그 객체에 저장해주는
역할을 한다.

그런데 위 FRONT 에서 지정해준 Content-type 은 multipart/form-data이다.
그러므로 위의 데이터 형식을 읽을 수 있게 라우터를 하나 생성하고,
그에 맞는 미들웨어 역시 사용해야 한다.

그런데 express.json() 과 express.urlencoded();는 express의 내장 함수이지만
multipart/form-data를 읽을 수 있는 함수는 존재하지 않으므로

외부라이브러리인 multer를 설치해서 사용할 것이다.

npm install 로 설치하고

$ npm install multer

require로 땡겨온다

const multer = require('multer');

그리고 multer 를 이용해서 객체를 생성해주면 된다.

const upload = multer({
  storage: multer.diskStorage({
    destination(req, file, done) {
      done(null, 'uploads/');
    },
    filename(req, file, done) {
      const ext = path.extname(file.originalname);
      const fileName = `${path.basename(
        file.originalname,
        ext
      )}_${Date.now()}${ext}`;
      done(null, fileName);
    },
  }),
  limits: { fileSize: 5 * 1024 * 1024 },
});

코드가 좀 지저분 하니까 조금 정리해보면

const storage = multer.diskStorage({
  destination(req, file, done) {
    done(null, 'uploads/');
  },

  filename(req, file, done) {
    const ext = path.extname(file.originalname);
    const fileName = `${path.basename(
      file.originalname,
      ext
    )}_${Date.now()}${ext}`;
    done(null, fileName);
  },
});
const limits = { fileSize: 5 * 1024 * 1024 };

const multerConfig = {
  storage,
  limits,
};

const upload = multer(multerConfig);

어째 더 지저분한거 같은건 기분 탓이려나

그래도 조금더 눈에 잘 들어오는 거 같기는 하다.

이렇게 설정을 해주면 이제부터 upload+method 로 프론트에서 전달해준 파일데이터를 다시 이미지로 변환하고
저장해주는 미들웨어를 사용할 수 있다.

upload 객체로 사용할 수있는 메서드중 업로드와 관련된건 3가지 이다.

  1. single
  2. array
  3. fields
    이다.

single 은 단 하나의 이미지만 업로드 할때,
array 는 하나의 input 에서 여러개의 파일을 업로드 할때,
fields는 여러개의 인풋에서 각각 하나의 파일을 업로드 할때 사용한다.

single은

app.post('/upload', upload.single('imgUpload'), (req, res) => {
  console.log(req.file);
  console.log(req.body.subject);
  res.send('upload!');
});

이렇게 사용하면, /upload 에 post 요청이 오면 single 메서드가 미들웨어로 동작하면서,
업로드 된 파일의 정보를 req.file에
그 이외의 내용을 req.body 에 저장하고
next() 함수가 실행된다.

array method 를 사용하기 위해서는
데이터를 전달해주는 input 태그에 multiple 이라는 속성이 추가 되어야 한다.

<input type="file" name="imgUpload" multiple />

라우터 작성법은 single과 동일하나,
전달되는 데이터가 여러개이다 보니,
req.file 이 아닌 req.files 라는 객체에 데이터가 저장되고,
저장되는 데이터의 형식도 배열로 저장된다.

마지막 fields 의 경우는 인자값으로
프론트에서 전달되는 모든 name 태그를 배열안의 객체형태로 담아줘야한다.

app.post(
  '/filedsUpload',
  upload.fields([
    { name: 'upload1' },
    { name: 'upload2' },
    { name: 'upload3' },
    { name: 'upload4' },
  ]),
  (req, res) => {
    console.log(req.files.upload1);
    console.log(req.body.subject);
    res.send('upload!');
  }
);

이렇게 해주면 된다.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <form method="post" action="/filedsUpload" enctype="multipart/form-data">
      <input type="text" name="subject" />
      <input type="file" name="upload1" />
      <input type="file" name="upload2" />
      <input type="file" name="upload3" />
      <input type="file" name="upload4" />
      <button type="submit">전송</button>
    </form>
  </body>
</html>

그리고 html은 이렇게 변경 해주었다.

전체 코드는 깃헙에 올라가 있다.

728x90
728x90

댓글