한국어로 번역된 설명이 있습니다.
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 속성으로 무엇을 업로드할 것인지 제한할 수 있는데, 오류를 줄이기 위해서라도 중요한 속성이다.
.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");
멀터 객체에 줄 수 있는 옵션은 다음과 같습니다.
- 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에 대한 내용은 아래 문서를 통해 살펴볼 수 있습니다.
좀 더 자세하게 한 페이지에 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);
});
});
'Node, Nest, Deno > 🚀 Node.js (+ Express)' 카테고리의 다른 글
Vanilla Node로 간단한 웹 서버 만들기 (0) | 2020.03.07 |
---|---|
Node.js가 제공하는 내장 객체, 변수, 모듈 (0) | 2020.03.07 |
mongodb으로 스키마, 모델 생성하기 (in node.js) (0) | 2020.02.27 |
도메인에 동적인 변수가 들어갔을 경우 실행 방법 (0) | 2020.02.18 |
mixin (0) | 2020.02.18 |