본문으로 바로가기

 

한국어로 번역된 설명이 있습니다. 

 

expressjs/multer

Node.js middleware for handling `multipart/form-data`. - expressjs/multer

github.com

 

 

npm install multer

node.js에서 이미지나 동영상 같은 파일을 올릴 때 multer를 사용하게 된다. multer는 이미지나 동영상을 제출하면 그것을 해석하는 역할을 맡는다.

 

- 최소한의 Hello world 코드

여기서 핵심만 짚자면

form에는 enctype을 multipart/form-data로 input에는 accept값을 준다는 것이다.

<form action="info" method="post" enctype="multipart/form-data">
  <label for="file">file</label>
  <input
    type="file" name="file" id="file" required="true" accept="application/JSON" />
  <input type="submit" />

 

백단에는 multer 객체를 하나 만든 후 (upload) 메소드를 활용하여 미들웨어로 통과시킨다. (upload.single())

업로드한 파일을 req.file에 존재한다.

const express = require("express");
const multer = require("multer");

// 각종 설정이 가능하나 우선은 빈 채로 두자.
const upload = multer({});

const app = express();

app.post("/info", upload.single("file"), (req, res) => {
  // req.file에 업로드한 파일 존재
  console.log(req.file);
});

 

여기서 multer 객체에 대한 설정을 자세히 살펴보아야 한다. 현재 상태로는 기본 스토리지(메모리)에 저장되어 새로고침하면 업로드한 파일이 사라지고, 파일 용량 제한도 두지 않은 상태다.

 

 

 - form과 input의 속성 (enctype, accept)

 

  보통 이미지나 동영상을 업로드하는 방식은 input[type=file]이 든 form을 통해 업로드한다. 이 때 form의 enctype을 multipart/form-data으로 해야 한다. 아직 곳에서는 작동하지 않는다. 그 예를 PUG로 작성한 바는 아래와 같다. 

 

input에서 accept 속성으로 무엇을 업로드할 것인지 제한할 수 있는데, 오류를 줄이기 위해서라도 중요한 속성이다.

 

HTML input accept Attribute

HTML accept Attribute ❮ HTML tag Example Specify what file types the user can pick from the file input dialog box:

      <input< p="">

www.w3schools.com

</input<>
.form-container
  form(action=`/videos${routes.upload}`, method="post", enctype="multipart/form-data")
    label(for="file") Video File
    input(type="file", id="file", name="file", required=true, accept="video/*")

 

 

 

 - multer 객체와 메서드(single, array...)

 

  post를 날리는 경로의 미들웨어에 muulter 객체의 메소드(single)을 두어 비디오를 업로드할 때 multer를 거처가도록 설정하자. 즉, multer를 이미지, 동영상 업로드시 거쳐가야 하는 미들웨어로 사용하자는 것이다. multer가 없다면 이미지, 동영상을 해석할 수 없다.

 

  여기서 중요한 것은 single('videoFile')이 제출하는 form 내부의 input 태그의 name 인자(videoFile)와 같아야 한다는 것이다. (multer에는 single 외에도 array, fileds, none이 존재하며 이미지나 동영상은 req.file 객체에 존재한다. single이 아니라 array 등 여러 개를 처리하면 req.files 가 됩니다. 그 외의 정보는 req.body에 담긴다)

input(type="file", id="file", name="videoFile", required=true, accept="video/*")

미들웨어 파일 속에 multer를 처리하는 미들웨어를 하나 만들어 보았습니다. single의 인자로 input의 name을 주면 됩니다. 저장 경로는 videos/라는 폴더 내에 저장하도록 설정했습니다.

import routes from "./routes";
import multer from "multer";

// multer를 거친 비디오는 videos 폴더 내부에 담기도록 설정합니다.
const multerVideo = multer({ dest: "videos/" });

export const uploadVideo = multerVideo.single("videoFile");

 

멀터 객체에 줄 수 있는 옵션은 다음과 같습니다.

 

expressjs/multer

Node.js middleware for handling `multipart/form-data`. - expressjs/multer

github.com

 

- req.file

 

파일을 하나 업로드한 후 req.file을 출력해보았습니다. 업로드된 파일은 노드 개장 모듈인 fs로 읽어서 활용하면 됩니다.

{
  fieldname: 'file',
  originalname: 'subtitle.json',
  encoding: '7bit',
  mimetype: 'application/json',
  destination: 'uploads/',
  filename: 'd1bd947daf026eee30a25fb4c7a857b1',
  path: 'uploads\\d1bd947daf026eee30a25fb4c7a857b1',
  size: 3704
}

parse 해야 읽을 수 있는 형태로 출력됩니다.

  const readfile = async () => {
    const file = fs.readFileSync("./uploads/d1bd947daf026eee30a25fb4c7a857b1");
    console.log(JSON.parse(file));
  };
  readfile();

 

한편, req.file에 대한 내용은 아래 문서를 통해 살펴볼 수 있습니다.

 

expressjs/multer

Node.js middleware for handling `multipart/form-data`. - expressjs/multer

github.com

 

 


 

좀 더 자세하게 한 페이지에 multer를 사용하는 예를 첨부했습니다.

 

multer의 속성을 정의하고 (저장 경로, 용량 제한 등) multer.single('name') 등을 이용해 가공하여 미들웨어로 활용합시다.

 

import express from "express";
import path from "path";
import multer from "multer";
import { read } from "fs";
import hashtag from "../models/hashtag";
import { Hashtag, Post } from "../models";

const uploadRouter = express.Router();

const upload = multer({
  // storage : 어디에 저장할 것인지
  // 서버 디스크에 저장하거나 AWS S3와 같은 외부에 저장합니다.
  // multer-s3나 multer-google-storage와 같은 모듈을 찾아서 활용해봅시다
  storage: multer.diskStorage({
    //destination은 저장할 경로. 동일 경로 내 uploads에 저장할 것임.
    // uploads 폴더를 생성해 둘 것.
    destination(req, file, cb) {
      cb(null, "uploads/");
    },
    // filename은 저장할 파일의 이름
    filename(req, file, cb) {
      // ext는 확장자 명을 말합니다.
      const ext = path.extname(file.originalname);
      // basename은 파일 이름입니다. 파일 이름 + 현재 시간 + 확장자로 정하겠습니다.
      //날짜를 붙이는 건 중복을 피하기 위함입니다.
      cb(
        null,
        path.basename(file.originalname, ext) + new Date().valueOf() + ext
      );
    }
  }),
  // limit : 파일 사이즈 제한 (byte 단위) 아래는 5mb 까지만 허용함을 의미
  limit: { fileSize: 5 * 1024 * 2014 }
});

// multer 미들웨어를 설정합니다.
// upload.single외에도 array, fields, none이 존재합니다.
// upload.single()에는 제출하는 input의 name을 적어주면 됩니다.
uploadRouter.post("/img", upload.single("img"), (req, res) => {
  // 멀터가 해석한 이미지나 동영상은 req.file 객체 내부에 담깁니다.
  // 그 외의 정보는 req.body에 담깁니다.
  console.log(req.body, req.file);
  res.json({ url: `/img/${req.file.filename}` });
});

const upload2 = multer({});
uploadRouter.post("/", upload2.none(), async (req, res, next) => {
  try {
    const post = await Post.create({
      content: req.body.content,
      img: req.body.url,
      userId: req.user.id
    });
    const hashtags = req.body.content.match(/#[^\s]*/g);
    if (hashtags) {
      await Promise.all(
        hashtags.map(tag =>
          // findOrCreate는 있으면 찾고 없으면 생성하라는 sequelize 명령어
          Hashtag.findOrCreate({ where: { title: tag.slice(1).toLowerCase() } })
        )
      );
      await post.addHashtags(result.map(r => r[0]));
    }
  } catch (err) {
    console.log(err);
    next(err);
  }
});

export default uploadRouter;

 


React + Express에는 다음과 같이 이용합니다.

 

// React에서 form 작성
<form onSubmit={handleForSubmit}>
 <h1>고객추가</h1>
 프로필 이미지 :
 <input type="file" name="file" file={file} value={fileName} onChange={handleFileChange}></input>

// FormData 생성자를 이용해 formdata를 구성합니다.
const addCustomer = () => {
  const url = `/api/customers`;
  const formData = new FormData();
  formData.append("image", file);
  formData.append("name", userName);
  formData.append("birthday", birthday);
  formData.append("gender", gender);
  formData.append("job", job);
  const config = {
    headers: {
      "content-type": "multipart/form-data",
    },
  };
  return post(url, formData, config);
};
// Express에서 multer 처리

// multer 객체 생성
const upload = multer({ dest: "./upload" });

// 유저가 접근하는 /image 경로는 ./upload 폴더와 매핑.
app.use("/image", express.static("./upload"));

app.post("/api/customers", upload.single("image"), (req, res) => {
  let sql = "INSERT INTO CUSTOMER VALUES (null, ?, ?, ?, ?, ?)";
  let image = "/image/" + req.file.filename;
  let name = req.body.name;
  let birthday = req.body.birthday;
  let gender = req.body.gender;
  let job = req.body.job;
  console.log(gender);
  // 각 물음표가 바인딩 되어서 들어감
  let params = [image, name, birthday, gender, job];
  connection.query(sql, params, (err, rows, fiedls) => {
    console.log(err);
    res.send(rows);
  });
});


darren, dev blog
블로그 이미지 DarrenKwonDev 님의 블로그
VISITOR 오늘 / 전체