npm install multer sharp @types/multer @types/sharp
import multer from 'multer';
import { mkdirSync, existsSync, writeFile } from 'fs';
import { join } from 'path';
import sharp from 'sharp';
const dir = join(__dirname, "..", "public", "images", "uploads");
const _storage = multer.diskStorage({
destination: (req, file, callback) => {
if (!existsSync(dir)) {
mkdirSync(dir, { recursive: true });
}
callback(null, dir);
},
filename: (req, file, callback) => {
callback(null, Date.now().valueOf() + "_" + file.originalname);
}
});
const upload = multer({ storage: _storage }); // upload 미들웨어
원하는 경로가 존재하지 않는다면 새로 폴더를 생성한다 recursive 속성을 사용하면 상위 폴더까지 생성할 수 있다
파일이름도 중복 문제가 있을 수 있기 때문에 Date.now 와 함께 쓴다
여기서 upload는 파일 업로드를 받을 수 있는 객체가 된다
registerRouter.post('/', upload.single('profile'), (req: Request, res: Response, next: NextFunction) => {
try {
sharp(req.file?.path) // 압축할 이미지 경로
.resize({ width: 600 }) // 비율을 유지하며 가로 크기 줄이기
.withMetadata() // 이미지의 exif 데이터 유지
.toBuffer((err, buffer) => {
if (err) next(err);
writeFile(req.file?.path!, buffer, (e) => {
if (e) next(e);
});
});
res.json({ filename: `${req.file?.filename}`});
} catch (error) {
next(error);
}
});
사용자로부터 post 요청을 받으면 upload.single(’profile’)이 실행된다
upload.single(’profile’) 는 요청받은 파일을 위에서 설정한 위치에 저장함과 동시에 req 객체에 file이라는 속성을 추가해서 관련 정보를 저장한다
이 때 profile은 front input name 속성이다
sharp로 이미지 리사이즈 해서 파일크기 압축효과를 얻을 수 있다
이미지 크기가 크면 이미지 로딩 시간이 길어질 수도 있기 때문에 압축한다
압축 후 writeFile을 통해 이미지를 저장해주면 기존 파일을 덮어씌우기 때문에 기존 파일을 삭제할 필요도 없고 충돌로 인한 오류도 나지 않는다
doctype html
html
head
meta(charset="utf-8")
title Bookitory
body
h2 Register
form(action="/register" method="post" id="register" enctype="multipart/form-data")
input(type="text" name="email" placeholder="email" autofocus)
br
input(type="password" name="password" placeholder="password")
br
input(type="file" name="profile" accept="image/png,image/jpg,image/jpeg")
br
button submit
script(type="text/javascript", src="/scripts/register/index.js")
image를 업로드 하기 위해 form enctype을 multipart/form-data로 지정해야한다