본문 바로가기
Back-End/🌿Express (nodeJS)

[Express] multer를 이용해서 백엔드 이미지 업로드

by 코딩하는 동현😎 2022. 11. 6.

multer 미들웨어

multer는 이미지 동영상등 여러가지 파일들을 멀티파트 형식으로 업로드 할때 사용하는 미들웨어 입니다.

멀티파트 형식이란것은 enctype속성(인코딩)이 multipart/form-data인 형식을 말합니다.

<form id="form" action="/upload" method="post" enctype="multipart/form-data">
enctype의 속성에는 아래와 같은 종류가 있습니다.
application/x-www-form-urlencoded   기본값으로, 모든 문자들은 서버로 보내기 전에 인코딩됨을 명시함.
multipart/form-data   모든 문자를 인코딩하지 않음을 명시함.
이 방식은 <form> 요소가 파일이나 이미지를 서버로 전송할 때 주로 사용함.
text/plain   공백 문자(space)는 "+" 기호로 변환하지만, 나머지 문자는 모두 인코딩되지 않음을 명시함.

 


npm으로 설치하기

해당폴더의 터미널에 아래와 같이 입력해주면 됩니다. (nodejs와 npm은 당연히 깔려있어야합니다.)

npm i multer

실습에 이용할 프론트 html

<form id="form" action="/upload" method="post" enctype="multipart/form-data">
    <input type="file" name="image" />
    <input type="text" name="title" />
    <button type="submit">업로드</button>
  </form>

 

 

실행예시

 

 

 

 

 

 


기본적인 설정

app.js 파일에 작성하시면 됩니다.

 

미들웨어를 사용하려면 먼저 require함수를 이용해서 가져와야합니다.

 

multer함수의 인수로 설정값을 넣을수 있습니다.

아래에는 storage와 limit 인수를 넣었습니다.

storage는 파일을 넣을 경로(destination)과 어떤 이름(filename)으로 저장할지를 설정할 수 있습니다.

 

destination과 filename함수에는 req,file,done인자가 있는데, req는 요청에 대한 정보, file은 받은 파일의 정보가 있습니다. done은 함수 입니다.

req나 file의 데이터의 정보를 가공해서 done이라는 함수에 넘겨주는 것입니다.

그래서 uploads 폴더에 본래이름 그대로 업로드 하는 코드입니다.

 

limits 속성은 파일크기 제한을 하는 것입니다. 아래는 5MB로 제한을 한 케이스 입니다. 

// multer 미들웨어 사용
const multer = require('multer');


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

upload 폴더에 저장하기로 코딩했는데, 그 폴더가 없으면 오류가 생기게 됩니다.

그래서 아래 코드를 더 추가해줍니다.

readdir, mkdir이랑 readdirSync,mkdirSync의 차이점은

Sync붙은 함수는 동기처리를 한다는 것입니다.

원래 nodejs는 비동기 처리로, 함수가 실행이 완료가 안돼도 다음함수로 넘어가서 동시에 처리하지만, 여기서는 순차적으로 (동시X) 처리할 필요가 있으므로 이 함수를 이용합니다.

const multer = require('multer');
const fs = require('fs');


try {
  fs.readdirSync('uploads');
} catch (error) {
  console.error('uploads 폴더가 없어 uploads 폴더를 생성합니다.');
  fs.mkdirSync('uploads');
}

라우터 객체로 요청을 받고 실행

일반 요청일땐 html파일을 띄어주고, post요청을 html로 받으면 위에서 정의해준 upload multer객체의 single함수(단일파일)를 호출해서 upload에서 기본설정한 대로 파일을 업로드 하게 됩니다.

 

single함수의 인자로 name을 받습니다. 이 name은 html form에서 설정해준 이름과 동일해야합니다.

<input type="file" name="image" />

router.get('/', (req , res)=>{
    res.sendFile(path.join(__dirname, 'multipart.html'));
})
router.post('/', upload.single('image'), (req, res) => {
    console.log(req.file);
    res.send('ok');
});

app.js 전체 코드 (수정)

const express = require('express');
const morgan = require('morgan');
const cookieParser = require('cookie-parser');
const session = require('express-session');
const dotenv = require('dotenv');
const path = require('path');

dotenv.config();
const app = express();
app.set('port', process.env.PORT || 3000);

app.use(morgan('dev'));
app.use('/', express.static(path.join(__dirname, 'public')));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser(process.env.COOKIE_SECRET));
app.use(session({
  resave: false,
  saveUninitialized: false,
  secret: process.env.COOKIE_SECRET,
  cookie: {
    httpOnly: true,
    secure: false,
  },
  name: 'session-cookie',
}));

const multer = require('multer');
const fs = require('fs');

try {
  fs.readdirSync('uploads');
} catch (error) {
  console.error('uploads 폴더가 없어 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);
      done(null, path.basename(file.originalname, ext) + Date.now() + ext);
    },
  }),
  limits: { fileSize: 5 * 1024 * 1024 },
});

//upload 루트 패스로 수정
app.get('/upload', (req, res) => {
  res.sendFile(path.join(__dirname, 'multipart.html'));
});
app.post('/upload', upload.single('image'), (req, res) => {
  console.log(req.file);
  res.send('ok');
});

app.listen(app.get('port'), () => {
  console.log(app.get('port'), '번 포트에서 대기 중');
});
반응형

댓글