ihl 2021. 5. 12. 21:09

upload file

  multer는 form-data를 다루기 위한 node.js 미들웨어이다. multer로 서버에 파일 업로드를 구현해보자.

 

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

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

  먼저 multer를 npm install한 후 옵션 객체와 함께 multer객체(upload)을 작성한다. 옵션 객체를 생략했다면 파일은 디스크가 아니라 메모리에 저장된다. multer의 옵션객체의 속성은 다음과 같다.

 

multer의 옵션객체

  옵션객체의 storage속성으로 사용된 diskStorage는 파일을 디스크에 저장하기 위한 제어기능을 제공하며 destination과 fileame 두가지 옵션이 존재한다.

 

  destination은 어느 폴더에 저장할지를 결정한다. 값이 없다면 OS의 임시파일 디렉토리를 사용한다. 위 코드에서는 upload라는 폴더를 사용했다. filename은 파일이름이며 값이 없다면 랜덤한 이름으로 지어진다.(확장자 없음) 사용자가 업로드한 파일은 이름이 겹칠 수 있으므로 Date정보를 이름에 추가하여 저장하였다.

 

const express = require('express');
const router = express.Router();

router.post('/upload', upload.single('file'), (req, res) => {
    console.log(req.file);
    console.log(req.body);
    res.json({ result : `${req.file.filename}`});
})

module.exports = router;

  작성한 multer 객체를 post의 인자로 넣으면 사용자가 업로드한 파일이 request 객체에 추가된다. 파일이 하나라면 single(), 여러개라면 array()를 사용한다. 이 외에도 fields()라는 메소드가 있는데 fields()는 인자에 명시된 파일만 받을 수 있다.(name, maxCount) single의 인자는 필드 이름이다. 즉, 클라이언트 form과 맞추어 주어야 한다.

 

const express = require('express');
const imgRouter = require('./routes/img');

const app = express();

app.use('/api', imgRouter);

app.use(express.static('uploads'));

app.listen(4000, () =>{
    console.log('4000번 포트 서버 실행');
})

  작성한 imgRouter를 /api 경로와 연결시켰다. 또한 업로드된 이미지를 정적파일로 제공하기 위해 express.static 모듈을 사용하였다.

 

import React, { useState } from 'react';
import './App.css';
import axios from 'axios';

function App() {
  const [img, setImage] = useState(null);

  const onChange = (e) => {
    setImage(e.target.files[0]);
  }

  const onClick = async () => {
    const formData = new FormData();
    formData.append('file', img);
    formData.append("filename", img.name);
    formData.append("title", "ihl");
    const res = await axios.post("http://localhost:4000/api/upload", formData);
  }

  return (
    <div className="App">
      <input type="file" onChange={onChange}/>
      <button onClick={onClick}>제출</button>
      <img src="http://localhost:4000/cleancode1620819855894.jpg"></img>
    </div>
  );
}

export default App;

  클라이언트측에서는 formData를 이용하여 서버에 파일을 업로드해야하므로 위와 같이 작성한다. 이 때 input태그의 type을 서버 multer.single() 메소드의 인자와 맞춘다.

 

서버에서 받은 데이터

  서버에서 받은 데이터는 위와 같다. 첫 번째 객체는 req.file, 두 번째 객체는 req.body이다. req.body에는 filename이 그대로지만 req.file의 내가 설정한대로 filename은 시간정보가 함께 포함되어 있다.

 

업로드된 파일

  업로드된 파일이다. 서버 uploads 폴더 내에 시간정보가 포함된 이름으로 잘 저장되어있다.

 


github.com/expressjs/multer/blob/master/doc/README-ko.md