Multer란 Node.js 미들웨어이다. HTML Form에서 multipart/form-data로 넘겨주는 데이터를 처리하기 위한 패키지이다.
처음에 Amazon S3 업로드를 구현했을 때, 파일스트림을 이용해 구현하였는데, 다음과 같은 문제점이 있었다.
따라서 multipart/form-data로 데이터를 넘겨, 일반 텍스트와 사진 데이터를 구분해 받을 수 있었고, 이를 처리하기 위해 Multer패키지를 이용하게 되었다.
Amazon S3와 묶어 사용했기 때문에, Amazon S3에 대해 설명한 후 같이 기술하겠다.
Amazon S3는 아마존에서 제공하는 클라우드 서비스이다.
앱 배포 시 Amazon EC2를 활용한 배포를 처음부터 생각중이었다. 그런데 Amazon EC2의 프리티어 사용시 스토리지의 용량은 불과 30GB밖에 되지 않았다. 그렇다고 내 PC를 서버로 이용해 배포하기엔 보안 측면에서도 유지 비용 측면에서도 크게 원하지 않는 방법이었다. 따라서 이미지 저장 공간을 분리해, 저장된 이미지의 URL을 불러온 후 그 이미지를 img src태그를 이용해 띄우는 방법을 생각해 냈다.
aws.js
const aws = require('aws-sdk');
const id = ''; // IAM ID
const secret = ''; // IAM 비밀번호
const s3 = new aws.S3({ accessKeyId:id, secretAccessKey:secret });
module.exports = s3;
multer.js
const multer = require('multer'); // multipart-data 처리를 통한 파일 업로드를 위한 multer
const multerS3 = require('multer-s3'); // multer를 활용, s3로 파일 업로드
s3 = require('./aws'); // aws config
// Multer를 위한 필터. 이미지 파일만 Multer를 통해 업로드하고 아닌 경우 에러 발생.
const multerfilter = (req, file, cb) => {
if (file.mimetype.startsWith('image')){
cb(null, true);
} else {
cb(console.log('Not image file upload tried'), false);
}
}
// multer 저장소 및 필터 설정
const upload = multer({
storage: multerS3({
s3: s3,
bucket: 'blogprojectbucket',
contentType: multerS3.AUTO_CONTENT_TYPE, // content type 들어오는대로 설정
key: function(req, file, cb){
if(file.originalname === undefined || file.originalname === null){ }
else {
cb(null, Date.now() + '.' + file.originalname.split('.').pop()); // 파일 이름 설정을 위한 callback function
}
}
}),
fileFilter: multerfilter,
},'NONE');
module.exports = upload;
index_admin.ejs
<form action="/api/insertAboutme" enctype="multipart/form-data" method="post" id="changeAboutmeForm">
...
<div class="row d-flex col-md-12 justify-content-center">
<div class="mb-1 col-md-8">
<div class="col-md-12">
<label for="postPhoto" class="form-label">사진 선택</label>
<input class="form-control form-control" id="postPhoto" type="file" name="postPhoto" accept="image/png, image/gif, image/jpeg">
</div>
</div>
</div>
...
routes/api.js
// /api
const express = require('express');
const { getAboutme, getAboutmeById, insertAboutme, updateAboutme, deleteAboutme, insertImage, insertPost, deletePost, updatePost } = require('../controllers/apiController');
const upload = require('../lib/multer');
const router = express.Router();
...
router.post('/insertAboutme', upload.single('postPhoto'), insertAboutme);
router.post('/updateAboutme/:postId',upload.single('postPhoto'), updateAboutme);
router.post('/deleteAboutme/:postId',upload.single(), deleteAboutme);
router.post('/insertImage', upload.single('img'), insertImage);
// upload.single()은 파일 한 개의 업로드를 지원하는 함수로서, 인자로 input file 태그의 name 요소를 전달한다.
...
// @post
// /api/insertAboutme
const insertAboutme = async(req, res) => {
...
if(req.file !== undefined) {
var imgurl = req.file.location; // router에서 붙인 multer가 반환한 url (aws s3 object url)
}
...
};
MariaDB에 저장된 이미지 URL들
AWS S3 Bucket에 저장된 이미지들
정상적으로 표시되는 이미지들.
HTML 소스 보기를 통해 본 이미지를 표시하는 모습