[express.js] multer와 s3를 통해 사진 업로드 기능 구현

김지엽·2023년 11월 23일
0
post-thumbnail
post-custom-banner

1. 개요

express 프로젝트에서 사진 업로드 기능을 담당하게 되어서 AWS s3와 multer 패키지를 통해서 기능을 구현해볼려고 한다.

AWS 버킷 생성 및 키 발급은 옆의 포스트에서 다루었다.

2. 로직 생각하기

포스트에 이미지를 업로드해서 데이터베이스에 저장하는 방식은 두가지를 생각했다.

- 이미지 url을 데이터베이스에 저장하기

자세한 로직은 다음과 같다.

저장

1. 클라이언트에서 중간중간에 input 태그를 통해서 이미지 넣기
2. 폼 형태로 서버로 모든 데이터 저장 요청
ex ) thumbnail, title, content, images
3. images를 s3에 저장후 url로 변환
3. DB에 저장

불러오기

1. 서버로 해당 포스트 데이터 요청
2. 포스트 내용 중간 중간 위치에 맞게 image 배치
3. 포스트 내용 보여주기

- 이미지 url을 포스트 내용에 저장하기

자세한 로직은 다음과 같다.

저장

1. 포스트를 쓸때 이미지를 넣을때마다 s3에 저장하고 url로 변환 후 포스트 내용에 넣기
2. 폼 형태로 서버로 데이터 저장 요청
ex ) thumbnail, title, content
3. DB에 저장

불러오기

1. 서버로 해당 포스트 데이터 요청
2. 포스트 내용 보여주기

3. multer와 s3 연동 미들웨어

- AWS s3 연동

aws에서 s3에 접근이 허용된 key를 통해 연동한다.

const s3 = new aws.S3({
    accessKeyId: process.env.AWS_S3_ACCESS_KEY_ID, // aws key
    secretAccessKey: process.env.AWS_S3_SECRET_ACCESS_KEY, // aws secret key
    region: process.env.AWS_S3_REGION // aws s3 region
});

- multer와 s3 연동

썸네일 multer s3

const uploadThumbnailMulter = multer({
    storage: multer_s3({
        s3, // s3 넣기
        bucket: AWS_S3_BUCKET_NAME, // s3 버킷 이름
        acl: "public-read-write", // s3 acl 읽기 및 쓰기
        key: (req, file, callback) => {
            // 확장자 지원 여부 확인
            const ext = path.extname(file.originalname);
            
            if (!imageExtensions.includes(ext)) {
                return callback(new Error("잘못된 파일 확장자입니다."));
            }
			// s3에 images 폴더에 파일 저장
            callback(null, `images/${Date.now()}_${file.originalname}`);
        }
    })
}).single("thumbnail"); // 이미지 한장 key값은 "thumbnail"로 설정

이미지 multer s3

const uploadImagesMulter = multer({
    storage: multer_s3({
        s3,
        bucket: AWS_S3_BUCKET_NAME,
        acl: "public-read-write",
        key: (req, file, callback) => {
            const ext = path.extname(file.originalname);
            
            if (!imageExtensions.includes(ext)) {
                return callback(new Error("잘못된 파일 확장자입니다."));
            }

            callback(null, `images/${Date.now()}_${file.originalname}`);
        }
    })
}).single("image");

- multer 미들웨어(에러처리)

일반적으로는 위에서 정한 uploadThumbnailMulter와 uploadImagesMulter를 바로 미들웨어로 연결해도 되지만 예외 처리가 되지 않아 서버가 바로 종료될수 있다.

따라서 다음과 같이 미들웨어로 한번 더 포장해서 사용한다.

썸네일 미들웨어

export const uploadThumbnail = (req, res, next) => {
    uploadThumbnailMulter(req, res, (err) => {
        if (err) {
            return res.status(500).json({
                ok: false,
                message: "썸네일 업로드 실패하였습니다."
            });
        }

        next();
    });
};

이미지 미들웨어

export const uploadImages = (req, res, next) => {
    uploadImagesMulter(req, res, (err) => {
        if (err) {
            return res.status(500).json({
                ok: false,
                message: "이미지 업로드 실패하였습니다."
            });
        }

        next();
    });
};

4. 라우터에 multer 미들웨어 연결

라우터에 이미지 미들웨어 연결하기

postRouter.post("/posts/image", uploadImages, async (req, res) => {
    if (!req.file || !req.file.location) {
        return res.status(400).json({
            ok: false,
            message: "사진 파일이 잘못되었습니다."
        });
    }

    return res.status(201).json({
        ok: true,
        message: "사진이 성공적으로 업로드 되엇습니다.",
        data: {
            image: req.file.location
        }
    });
});

참고

npm multer
multer s3 저장소 연결
multer 미들웨어 에러처리

profile
욕심 많은 개발자
post-custom-banner

0개의 댓글