(Node.js) Multipart Form Data

Mirrer·2022년 9월 26일
0

Node.js

목록 보기
10/12
post-thumbnail

Multer

Mulitpart Form형식의 데이터를 Backend Server에서 처리하기 위해 사용되는 Middleware

Form에서 전달하는 데이터는 크게 Text, File 2가지로 구분할 수 있으며 app.js파일에서는 다음과 같이 클라이언트 Text 데이터를 처리했다.

app.use(express.json()); // axios로 데이터 보낼 때
app.use(express.urlencoded({ extended: true })); // 일반 form을 보낼 때

하지만 File(이미지, 동영상...등)과 같은 데이터를 처리하기 위해서는 추가로 Multer라는 Middleware를 사용해야 한다.

Multer다양한 타입의 파일들을 Multipart 형식으로 업로드하는 Middleware이다.

여기서 Multipart 형식이란 enctypemultipart/form-dataForm을 통해 업로드하는 데이터의 형식을 의미한다.

<Form encType="multipart/form-data">
    :
    :
</Form>

Upload Process

클라이언트에서 서버로 Form Data를 전송하는 방법은 크게 2가지가 있다.

Browser에서 Backend ServerForm Data를 한번에 전송하는 방식
Browser에서 Backend ServerForm Data를 나눠서 전송하는 방식

Form Data를 한번에 전송하는 방식은 Backend Server에서 데이터를 처리하기 편하지만, 한번에 전송하기 때문에 이미지 미리보기, 처리 시간이 오래 걸린다는 단점이 있다.

반면에 Form Data를 나눠서 전송하는 방식(Multipart 방식)이미지를 우선적으로 전송하여 서버에 업로드한 뒤 파일명만 Return하기 때문에 서버쪽에서 전달받은 주소를 통해 위의 단점을 해결할 수 있다.

본 포스팅에서는 Multipart 방식을 사용하여 설명해보겠다.


사용 방법

Multer 설치

아래 npm명령어를 통해 Multer Middleware를 설치한다.

npm i multer

Multer Settings

일반적인 Middlewareapp.js에서 모든 라우터에 공통으로 적용한다.

하지만 Form각각의 Form마다 데이터 전송 방식, 데이터 형식...등이 달라 해당 라우터에 개별적으로 적용한다.

  • upload setting

upload setting에서는 파일의 저장위치를 설정한다.

const multer = require('multer'); // multer 불러오기
const fs = require('fs'); // fs모듈 불러오기

// file system을 조작하는 fs모듈로 uploads폴더 생성
try {
  fs.accessSync('uploads'); // uploads파일이 존재하는지 확인
} catch (error) {
  console.log('uploads 폴더가 존재하지 않아 생성합니다.');
  fs.mkdirSync('uploads'); // uploads파일을 생성
} 

const upload = multer({
  storage: multer.diskStorage({ // 저장 위치 (diskStorage: 컴퓨터의 하드디스크)
    destination(req, file, done) { 
      done(null, 'uploads'); // uploads폴더에 저장
    },

  • filename setting

Node.js는 파일명이 중복되면 기존 파일을 덮어씌운다, 그래서 다음과 같이 파일명에 업로드날짜를 추가하여 이를 해결한다.

// routes.post.js
const multer = require('multer');
const path = require('path'); // path모듈 불러오기
const fs = require('fs'); 

try {
  fs.accessSync('uploads');
} catch (error) {
  console.log('uploads 폴더가 존재하지 않아 생성합니다.');
  fs.mkdirSync('uploads');
} 

const upload = multer({
  storage: multer.diskStorage({
    destination(req, file, done) { 
      done(null, 'uploads');
    },	
    filename(req, file, done) { // 업로드파일.png
      const ext = path.extname(file.originalname); // 확장자 추출(.png)
      const basename = path.basename(file.originalname, ext); // 파일명 추출(업로드파일)
      done(null, basename + '_' + new Date().getTime() + ext); // 파일명에 업로드날짜 추가(업로드파일_20220101.png)
    },
  }),
});

  • filesize setting

다음과 같이 업로드 파일의 크기를 설정한다.

// routes.post.js
const multer = require('multer');
const path = require('path');
const fs = require('fs'); 

try {
  fs.accessSync('uploads');
} catch (error) {
  console.log('uploads 폴더가 존재하지 않아 생성합니다.');
  fs.mkdirSync('uploads');
} 

const upload = multer({
  storage: multer.diskStorage({
    destination(req, file, done) { 
      done(null, 'uploads');
    },	
    filename(req, file, done) {
      const ext = path.extname(file.originalname);
      const basename = path.basename(file.originalname, ext); 
      done(null, basename + '_' + new Date().getTime() + ext);
    },
  }),
  limits: { fileSize: 20 * 1024 * 1024 } // 파일 크기 제한(20MB)
});

  • router 작성
// routes.post.js
// <input type='file' name='images' /> 클라이언트에서 이미지를 업로드

router.post('/images', isLoggedIn, upload.array('images'), async (req, res, next) => { // POST /post/images
  console.log(req.files); // 업로드 정보
  res.json(req.files.map((v) => v.filename)); // 파일명 전달
});

클라이언트에서 업로드한 이미지는 라우터의 upload.array('input name')로 전달된다.

이후 위에서 설정한 upload setting과정을 거친 뒤 라우터가 실행된다.

또한 업로드 타입에 맞게 다음과 같이 설정할 수 있다.

<input type='file' name='images' />

// input에서 업로드한 데이터가 text, json
upload.none()

// input에서 업로드한 데이터가 이미지 1장
upload.single('images')

// input에서 업로드한 데이터가 이미지 1장이상
upload.array('images')


<input type='file' name='images1' />
<input type='file' name='images2' />
  
// 다수의 input에서 업로드한 데이터  
upload.fields([{ name: 'images1' }, { name: 'images2' }])


Express.Static

Express.Static은 이미지나 텍스트 파일...등과 같은 정적인 파일을 서비스

정적 파일이란, Image, CSS, JavaScript 파일...등과 같이 직접 값에 변화를 주지 않는 이상 변하지 않는 파일을 의미한다.

Express.js는 이러한 정적 파일들을 손쉽게 제공할 수 있게 Static 이라는 Middleware를 제공한다.

Multer를 사용해 처리한 업로드파일을 Browser에서 출력하면 다음과 같이 Front Server를 참조하고 있어 오류가 발생한다.

<input type='file' name='images' />
<div>
  {imagePaths.map((v) => {
	<img src={`http://localhost:3065/${v}`} />
  })}
</div>

위 문제는 Express.static Middleware를 사용하여 Express.jsBackend Server의 업로드파일을 참조할 수 있게 하여 해결할 수 있다.


사용 방법

Static MiddlewareExpress.js가 기본적으로 제공하는 기능으로 별도의 설치 없이 다음과 같이 사용할 수 있다.

// app.js

const path = require('path');

// '/'는 서버주소('localhost3065/')를 의미
// path.join을 통해 현재 디렉토리이름(back) + 'uploads'로 수정
app.use('/', express.static(path.join(__dirname, 'uploads')));

참고 자료

Node.js 공식문서
Node.js 교과서 - 조현영
React로 NodeBird SNS 만들기 - 제로초

profile
memories Of A front-end web developer

0개의 댓글