nodejs์์ ์ด๋ฏธ์ง ๋ฑ์ ํ์ผ์ ๋ฉํฐํํธ ํ์์ผ๋ก ์ ๋ก๋ํ ๋ multer ๋ผ๋ ํจํค์ง๋ฅผ ์ค์นํด์ ๋ฏธ๋ค์จ์ด๋ก ์ด์ฉํ๋ค.
npm i multer
npm i multer-s3 aws-sdk
s3.json
{
"accessKeyId": "AKIAVLEU2D2EIKMGBVQS",
"secretAccessKey": "",
"region": "ap-northeast-2"
}
์ด์ ํฌ์คํ
์์ IAM์ ์ค์ ํ๊ณ ๋ฐ์ ์ด์ธ์คํค์ ์ํฌ๋ฆฟํค๋ฅผ ๋ฃ์ด๋๋ค. ์ด ์ํฌ๋ฆฟ ํค๊ฐ ์ ์ถ์ด ๋๋ฉด ์ฒญ๊ตฌ์์ ์์ฒญ๋ ์ก์๊ฐ ์ฐํ๊ณ ์ถ์ด ๊ฒจ์ธ์ ํ๊ด๋ฌธ ๋ฐ์ผ๋ก ๋ด์ซ๊ธธ์๋ ์์ผ๋๊น ๊ผญ๊ผญ ์ฃผ์ํ๋ค. region์๋ s3 ๋ฒํท์ ์ค์ ๋ ๋ฆฌ์ ์ ์ ๋๋ค. ์์ธ์ด๋๊น ๋ณดํต์ ap-northeast-2
๋ก ๋์ด ์์๊ฑธ.
multer.js
multer์ ๊ด๋ จ๋ ํ์ผ์ ์์ฑํ๋ค. config ๋๋ ํ ๋ฆฌ ์์ ๋ง๋ค์ด์ฃผ์๋ค.
const multer = require('multer');
const multerS3 = require('multer-s3');
const aws = require('aws-sdk');
aws.config.loadFromPath(__dirname + '/s3.json');
const s3 = new aws.S3();
const uploadReview = multer({
storage: multerS3({
s3: s3,
bucket: 'bjclone',
acl: 'public-read',
key: function (req, file, cb) {
cb(null, 'review/' + Date.now() + '.' + file.originalname.split('.').pop());
},
}),
limits: { fileSize: 1000 * 1000 * 10 },
});
const uploadItem = multer({
storage: multerS3({
s3: s3,
bucket: 'bjclone',
acl: 'public-read',
key: function (req, file, cb) {
cb(null, 'item/' + Date.now() + '.' + file.originalname.split('.').pop());
},
}),
limits: { fileSize: 1000 * 1000 * 3 },
});
module.exports = {
uploadReview,
uploadItem,
};
aws-sdk๋ฅผ ๊ฐ์ ธ์์ ์ด๊ธฐํํ๋ค. ์์์ ๋ฏธ๋ฆฌ ๋ง๋ค์ด๋ s3.jsonํ์ผ๋ก ์ด์ธ์ค ์ ๋ณด๋ฅผ ๋ด๋๋ค.
๋ผ์ฐํธ๋ง๋ค ๊ฐ๊ฐ ๋ค๋ฅธ ๋๋ ํ ๋ฆฌ์ ์ ์ฅํ๊ธฐ ์ํด์ upload ํจ์๋ฅผ ๋๋ก ๋ง๋ค์๋ค.
ํ๋๋ review/
์, ํ๋๋ item/
๋๋ ํ ๋ฆฌ ์๋์ ์ ์ฅ๋๋๋ก.
key
์ ๋ด๋ ํจ์์ ์ฝ๋ฐฑ์์ ์ ์ฅ๋ ์ด๋ฏธ์ง์ ์ด๋ฆ์ ์ค์ ํ๋ค.
๋๋ ํ ๋ฆฌ + ํ์ฌ์๊ฐ + ํ์ฅ์๋ช ์ผ๋ก ์ง์๋ค.
limits
๋ก ์ ์ฅ๋ ํ์ผ์ ์ฌ์ด์ฆ์ ์ํ์ ์ ํ ์ ์๋ค.
์ ํ ์ฌ์ด์ฆ๋ฅผ ๋์ด๊ฐ๋ฉด ์ค๋ฅ๋ฅผ ์ฝ๋ฐฑ์ผ๋ก ๋ฐํํ๋ค. ๋์ค์ ๋ค์ ๋ณผ ์์ .
Route.js
const res = require('express/lib/response');
const upload = require('../../../config/multer');
module.exports = function (app) {
const item = require('./itemController');
const jwtMiddleware = require('../../../config/jwtMiddleware');
// 1. ์ํ๋ฑ๋ก API (+ ํ๊ทธ, ์ํ์ด๋ฏธ์ง ๋ฑ)
app.post('/api/items', jwtMiddleware, upload.uploadItem.array('image', 12), item.postItems);
// 2. ์ํ์์ API
app.put('/api/items/:itemId', jwtMiddleware, upload.uploadItem.array('image', 12), item.putItems);
..
}
์ต์คํ๋ ์ค์ ๋ผ์ฐํธ ๋ถ๋ถ๋ง ๋ชจ์๋์ ํ์ผ์ด๋ค. upload๋ผ๋ ์ด๋ฆ์ผ๋ก multer.js
๋ฅผ ๋ถ๋ฌ์์ ์ฌ์ฉํ๋ค. ์ด ๋ถ๋ถ์ ์ํ์ ๋ฑ๋กํ๋ api์ด๋ฏ๋ก upload.uploadItem
์ ๋ฏธ๋ค์จ์ด๋ก ๋ฃ์ด์ฃผ์๋ค.
array('image',12)
: ์ต๋ 12๊ฐ์ ํ์ผ์ image๋ผ๋ ์ด๋ฆ์ผ๋ก ๋ฐ๋๋ค.
์ฌ๋ฌ๊ฐ์ ํ์ผ์ ๋ฐ์ ๋ array
๋ฅผ ์ฌ์ฉํ๋ค. ํ ๊ฐ์ ํ์ผ๋ง ๋ฐ์ ๋๋ single
์ ์ฐ๋ฉด ๋๋ค.
Controller.js
const postItems = async (req, res) => {
const postBody = req.body; //ํด๋ผ์์ ๋์ด์จ ๊ฐ
const userIdFromJWT = req.verifiedToken.userId;
const postImage = req.files; // ์ด๋ฏธ์ง ํ์ผ
if (!userIdFromJWT) {
return res.send(errResponse(baseResponse.TOKEN_VERIFICATION_FAILURE)); //3000
}
const imageKey = [];
if (postImage) {
postImage.forEach((v) => {
imageKey.push(v.key);
});
}
const postItemsResponse = await itemService.createItem(postBody, userIdFromJWT, imageKey);
return res.send(postItemsResponse);
};
api ์์ฒญ์ ๋ฐ์์ ์ค๋ ๊ณณ์ ์ด ํจ์์ด๋ค. multer๋ก ๋ฐ์ ํ์ผ๋ค์ req.files
๋ก ๋ฐ์ ์ ์๋ค. formdata์ ๊ฐ์ด ๋ด๊ธด ๋ค๋ฅธ ๋ฐ์ดํฐ๋ค์ ๋๊ฐ์ด req.body
๋ก ๋ฐ์์จ๋ค.
์์๋ก ์ด๋ฏธ์ง๋ฅผ ๋๊ฐ ์
๋ก๋ํด๋ณด์๋ค. location์ ์
๋ก๋๋ ์ด๋ฏธ์ง์ ์ฃผ์๊ฐ ๋ณด์ธ๋ค. ์๋ง์กดaws๋ท์ปด ์ด์ฉ๊ตฌ์ ์ฉ๊ตฌ์์ ์ด์ฉ๊ตฌ์ ์ฉ๊ตฌ
๊ฐ s3์ ์ ์ฅ๋ ์ด๋ฏธ์ง์ ์ด๋ฆ์ด๋ค. ๊ทธ ์ด๋ฆ์ key
๋ผ๋ ์ด๋ฆ์ผ๋ก ๋ฐ๋ก ์๋ค. ์ key๋ฅผ ์ฐ๋ฆฌ ์๋น์ค์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅํด์ ์ฐ๋ฉด ๋๋ค. ๋ค์ ํด๋ผ์ด์ธํธ์์ ์์ฒญํ ๋ key๋ง ๋ค์ ๋ด๋ ค์ฃผ๋ฉด, ํด๋ผ์ด์ธํธ ๋จ์์ ์๋ง์กดaws๋ท์ปด ๋ค์ ์ด์ฉ๊ตฌ์ ์ฉ๊ตฌ๋ฅผ ๋ถ์ฌ์ ์ฌ์ฉํ๋๋ก ํ๋ค.
์ด๋ ๊ฒ ์ด๋ฏธ์ง ์ ๋ก๋๋ฅผ ๊ตฌํํ๊ณ ๋์ ๋ฟ๋ฏํดํ๊ณ ์์ ๋ ์๋ฆผ์ด ์ธ๋ ธ๋ค. ์ผ,, ์๋ฌ ๋ก๊ทธ ์ฐํ๋ค ๋ด๋ฐ๋ผ.
์ด๋ฏธ์ง ํ์ผ์ ์ฉ๋์ด limit๋ณด๋ค ํฐ ๊ฒฝ์ฐ์ ์ด๋ฏธ์ง์ ํ์์ด ์ค์ ํด๋ ํ์์ด ์๋ ๋ ๋ฑ๋ฑ multer์์ ์๋ฌ๋ฅผ ๋ฐํํ๋ค. ๊ทธ ์๋ฌ๋ upload ํจ์์ ์ฝ๋ฐฑ์์ ํธ๋ค๋งํ ์ ์๋ค. ์ด์ฌํ ์ฐพ์๋ณด๋ ์ฝ๋ฐฑํจ์ ์์์ ์๋ฌ๋ฅผ ์ ์ดํ๋ค๋๋ฐ... ๋ฏธ๋ค์จ์ด๋ก multer์ ์ธ ๋ ์ด๋ค์์ผ๋ก ๊ทธ ์๋ฌ๋ฅผ ๋๊ฒจ์ผ ํ ์ง ๋ชจ๋ฅด๊ฒ ๋ค. ์กฐ๊ธ ๋ ์ฐพ์๋ด์ผ๊ฒ ๋คใ ใ