들어가기 전
이번 글에서는 Multer패키지를 이용하여 Multipart/Form-Data로 프론트에서 백엔드로 사진을 업로드하는 과정에 대하여 알아보겠다. 사진을 업로드하는 경우는 2가지로 나눠서 볼건데 첫번째는 처음에 게시글을 작성할때 올리는 경우와 올린 게시물의 사진을 수정하여 재업로드하는 경우로 나누어서 알아보자.
Multer? Multipart/Form-Data?
사용법을 알아보기 전 Multer가 무엇인지 Multipart/Form-Data가 무엇인지에 대해 알아보자. 먼저 multer는 node.js의 패키지인데 이미지, 텍스트, 동영상 등 각종 파일을 업로드할때 사용되는 패키지이다.
multipart/form-data는 HTTP의 전송 방식 중 하나인데 간단하게 말하자면 전송 데이터의 형식이 텍스트, 파일 등 여러가지의 데이터 타입이 한번에 전송되어야 할 때 사용되는 타입이다. 고로 보통 파일을 전송할때 사용되는 타입이라고 생각하면 된다.
정리하자면 프론트에서 multipart/form-data로 파일과 텍스트 등 데이터를 백엔드로 전송하면 백엔드에서는 multer패키지를 이용하여 파일을 받아서 지정한 위치에 파일을 저장하는 것이다.
사용법 - Multer
먼저 multer에 대한 사용법을 알아보자면
//서버의 로컬스토리지에 저장하는 로직
const upload = multer.diskStorage({
destination:function (req,files,cb){
cb(null,'uploads')
},
filename: function(req,files,cb){
cb(null,file.originalname+'/'+Date.now())
}
});
이런 코드를 통해 저장을 하면 된다. 자세하게 말하자면 multer를 이용하여 uploads라는 경로에 파일을 저장하고 파일의 이름은 파일 원본 이름에 / 와 저장 날짜를 합쳐서 저장하게되는 메서드를 만들어서 여기저기서 활용하는 것이다.
즉 upload를 미들웨어 형태로 사용하는 방식으로 이런 형식으로 사용하면 router에서 각 api로 요청을 보내기 전 필요할때 먼저 파일을 처리하고 그 다음에 api를 실행하는 방식으로 활용할 수 있다.
이렇게 아래처럼 작성을 하면 엔드포인트가 /communitydetail 이라는 post 요청이 오면 먼저 authMiddleware에 가서 올바른 이용자가 맞는지 확인하고 upload를 이용하여 사진 파일을 지정한 저장소에 저장을 하고 마지막으로 요청한 api를 처리하는 메서드로 넘어가는 방식이다.
// 라우터에서 미들웨어를 거쳐서 api로 이동하는 방법
router.post(
"/communitydetail",
authMiddleware, // api를 요청한 사람이 올바른 권한을 가지고 있는지 확인 하는 미들웨어
upload.array("photos[]", 1), // array는 사진이 여러장 일때 사용 하나면 single사용해도 된다.
uploadController.newImage
);
이렇게 하면 Multer를 기본적으로 사용한다고 할 수 있다. 간단하게 정리를 해보자면
- multer를 설치
- multer 패키지의 메서드(diskStorage)를 이용하여 파일 저장을 하는 로직을 메서드(upload)로 만들기
- upload메서드를 사용하고자 하는 메서드 전에 미들웨어로 사용하거나 메서드 내에서 직접 사용
이렇게 된다고 할 수 있다.
사용법 - multer-s3
이제 Multer에 대한 기본적인 사용방법을 알았는데 multer-s3는 또 뭐냐 라고 생각할 수 있다.
사실 multer나 multer-s3간의 개념적인 차이점은 사실상 없다고 할 수 있다. 그럼 개념적인 차이점이 없다면 사용법에서 차이가 있나?
맞다, multer가 로컬 스토리지에 저장하는데 사용되는 패키지라고 한다면 multer-s3는 AWS S3에 저장을 할 때 사용하는 패키지이다.
저장되는 위치가 다르기 때문에 AWS S3에 연결을 하고 연결된 S3의 버킷 중 어느 버킷에 어떤 형식으로 저장할 지 등 추가적인 동작이 필요하다. 하지만 개념적인 부분은 똑같이 클라이언트로 부터 받은 파일을 원하는 곳에 저장한다는 것에서 보면 완벽하게 동일하다.
즉 multer를 사용할 줄 안다면 multer-s3도 사용하는데 무리가 없다. 대신 S3를 저장소로 활용하기 때문에 당연히 S3에 대한 개념과 사용법은 알고 있어야한다.
※ AWS S3란?
AWS에서 제공하는 객체 스토리지 서비스이다. Simple Storage Service의 약자가 S3이다. 이름에서 부터 알 수 있듯이 사용법이 간단하고 업로드 다운로드를 위한 API가 있는 등 유용한 기능이 많아 정적인 요소들이나 사진, 텍스트 등 저장소로 굉장히 많이 사용되는 서비스이다. 자세한 내용은 AWS S3 페이지에서 알아보도록 하자
말했듯이 multer-s3의 사용법은 multer와 거의 비슷하므로 s3에 저장을 하는 upload메서드만 어떻게 다른지 살펴보겠다.
require("dotenv").config();
const multer = require('multer');
const Sequelize=require('sequelize');
const multerS3 = require('multer-s3');
const { S3, GetObjectCommand } = require('@aws-sdk/client-s3');
const {getSignedUrl}=require('@aws-sdk/s3-request-presigner');
//저장소 연결을 위한 객체 선언 즉 해당 id와 key를 가진 S3에 연결되어 저장하고 보내는 것이다.
const s3 = new S3({
credentials: {
accessKeyId: process.env.AWS_ACCESSKEY,
secretAccessKey: process.env.AWS_SECRETACCESSKEY
},
region: 'ap-northeast-2' // 저장소 위치
});
//사진 업로드 메서드
const upload = multer({
storage: multerS3({
s3: s3,
bucket: 'journeymate',
// acl: 'public-read',
contentType: multerS3.AUTO_CONTENT_TYPE,
key: function (req, file, cb) {
cb(null, `img/${Date.now()}-${file.originalname}`);
},
}),
});
// 프로필 사진 업로드
const profile = multer({
storage: multerS3({
s3: s3,
bucket: 'journeymate',
// acl: 'public-read',
contentType: multerS3.AUTO_CONTENT_TYPE,
key: function (req, file, cb) {
cb(null, `profileImage/${req.decode.userID}-${file.originalname}`);
},
}),
});
//채팅에서 사진 업로드
const chatting = multer({
storage: multerS3({
s3: s3,
bucket: 'journeymate',
contentType: multerS3.AUTO_CONTENT_TYPE,
key:function(req, file, cb){
cb(null, `chatting/${req.params.chatID}-${req.decode.userID}-${Date.now()}-${file.originalname}`)
}
})
})
//미리보기 url 전송
const getPreSignedUrl = async (key) => {
console.log(key)
try {
const filename = encodeURIComponent(key);
const command = new GetObjectCommand({
Bucket: "journeymate",
Key: key,
ResponseContentDisposition: "attachment; filename=\"" + key + "\"",
});
const url = await getSignedUrl(s3, command, { expiresIn: 60 });
console.log(url);
return url;
} catch (err) {
console.error("Error creating pre-signed URL:", err);
throw err;
}
};
const sequelize = new Sequelize(process.env.MYSQL_DATABASE, process.env.MYSQL_USERNAME, process.env.MYSQL_PASSWORD, {
host: process.env.MYSQL_HOST,
port: process.env.MYSQL_PORT,
dialect: 'mysql',
});
module.exports = {getPreSignedUrl,upload,profile, chatting, sequelize};
이게 최종적인 s3에 파일을 저장하는 로직이고 당연하지만 S3에 연결하기 위한 ID와 key는 .env파일에 저장하고 사용해야 한다.
위 코드를 통해 알 수 있듯이 저장소는 같지만 버킷을 다르게 할 수 도 있고 버킷은 같지만 하위 폴더를 만들어 각 폴더 별로 저장을 할 수 도 있다.
정리
multer는 어떤 흐름으로 사용하고 저장 로직은 어떻게 만들어야 하는지 알아보았다. 다음 글에서는 채팅 기능을 위한 Socket.io에 대해 알아보겠다.
'Node.js(Express)' 카테고리의 다른 글
| [Node.js] Modbus TCP를 이용한 공장 원격 관리 서버 제작 (0) | 2024.08.06 |
|---|---|
| [Node.js] 게시판 글 수정하기(사진 포함) (0) | 2024.02.07 |
| [Node.js] SNS 만들기 - Nodemailer를 이용한 사용자 인증 (0) | 2024.01.22 |
| [Node.js] JWT 사용하기 - access token, refresh token (0) | 2024.01.20 |
| [Node.js] JWT에 대해 알아보기 (0) | 2024.01.18 |