S3 + Multer를 이용한 Image Upload

Evan Lee ㅣ 2023. 1. 11. 21:02

현재 MERN 프로젝트에서는 Image를 multer를 이용해서 local에 직접 이미지를 저장해서 사용하고 있었습니다. 하지만 이렇게 하다보니까 문제가 생겼습니다. 배포된 서버에서 이미지를 처음에 올리고 나서는 괜찮았지만 다음번에 접속하면 해당 이미지파일이 사라졌는지 모르겠지만 제대로 이미지를 보내주지 않더군요. 

file upload code

 

그리고 제가 알기로는 이상적으로 이미지를 관리하려면 따로 이미지만 다루는 스토리지를 구축하고 DB에서는 해당 이미지에 대한 full path를 제공하는거라고 알고 있습니다. 

 

일단 S3 Bucket을 만들어야합니다. 

 

이와 같이 체크할 거 체크해주고, 버킷만들어줍니다. 

 

IAM 에서 사용자 추가를 해줍니다.

접근을 하기위해서 엑세스 ID랑 비밀 엑세스 ID를 가져야하거든요.

 

 

S3 Bucket으로 가서 정책을 수정해줘야합니다. 

편집을 누르고 아래 정책을 넣어줍니다. 

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicListGet",
            "Effect": "Allow",
            "Principal": "*",
            "Action": [
                "s3:GetObject",
                "s3:PutObject"
            ],
            "Resource": "arn:aws:s3:::{bucket name}/*"
        }
    ]
}

 

그리고 이제 아까 IAM 사용자 추가하면서 받았던 엑세스 아이디와 비밀 엑세스아이디, 그리고 서버 지역까지 awsconfig.json에 담아서 밑에 코드 처럼하셔도 되지만,

 

// file-upload.js

const AWS = require('aws-sdk');
const here = path.join(__dirname, '..', '/awsconfig.json')
AWS.config.loadFromPath(here);




// awsconfig.json

{
  "accessKeyId": "AKIAUEDLWK3XXIP2ES7E",
  "secretAccessKey": "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",
  "region": "ap-northeast-2"
}

https://docs.aws.amazon.com/ko_kr/sdk-for-javascript/v2/developer-guide/loading-node-credentials-json-file.html

 

JSON 파일에서 Node.js에 인증 자격 증명 로드 - AWS SDK for JavaScript

JSON 문서에서 구성 데이터를 로드하면 기존 구성 데이터가 모두 재설정됩니다. 이 기술을 사용한 후 추가 구성 데이터를 추가합니다. JSON 문서에서 인증 자격 증명을 로드하는 것은 브라우저 스

docs.aws.amazon.com

 

환경 변수에 추가해서 편하게 이렇게 하셔도 됩니다.

const creds = new AWS.Credentials({
  accessKeyId: process.env.S3_ACCESS_KEY_ID, 
  secretAccessKey: process.env.S3_SECRET_ACCESS_KEY
});

const myAWS = new AWS.Config({
  credentials: creds,
  region: process.env.S3_REGION,
})

AWS.config.update(myAWS);

https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/global-config-object.html

 

Using the Global Configuration Object - AWS SDK for JavaScript

Thanks for letting us know this page needs work. We're sorry we let you down. If you've got a moment, please tell us how we can make the documentation better.

docs.aws.amazon.com

https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Credentials.html#constructor-property

 

Class: AWS.Credentials — AWS SDK for JavaScript

The modular AWS SDK for JavaScript (v3), the latest major version of AWS SDK for JavaScript, is now stable and recommended for general use. For more information, see the Migration Guide and API Reference. Class: AWS.Credentials Inherits: Object Object AWS.

docs.aws.amazon.com

 

 

그리고 나서 이제 controller에서 응답 보내줄때 image를 s3 bucket에 담겨있는 key값으로 보내주고, 프론트쪽에서는 bucket 링크만 환경변수로 지정하고 image src에다가 넣어주면 정상 동작이 됩니다. 

MongoDB 전과 후 / image가 달라짐

 

file-upload 최종 코드 

const multer = require('multer')
const multerS3 = require('multer-s3');
const AWS = require('aws-sdk');
require('dotenv').config();

// 환경 변수에서 엑세스 키 가져와 새로운 AWS.Credentials 객체 생성
const creds = new AWS.Credentials({
  accessKeyId: process.env.S3_ACCESS_KEY_ID, 
  secretAccessKey: process.env.S3_SECRET_ACCESS_KEY
});

// 환경 변수에서 Region과 기존 Credentials 객체를 가져와 
// 나만의 configuration 새로 설정합니다.
const myAWS = new AWS.Config({
  credentials: creds,
  region: process.env.S3_REGION,
})

// 새로 설정된 configuration을 업데이트 해줍니다.
AWS.config.update(myAWS);

// 업로드할 수 있는 이미지 타입 설정
const MIME_TYPE_MAP = {
  'image/png': 'png',
  'image/jpg': 'jpg',
  'image/jpeg': 'jpeg',
}

const fileUpload = multer({
  limits: { fileSize: 500000 },
  storage: multerS3({
      s3: new AWS.S3(),
      bucket: 'place-ive-been',
      acl: 'public-read',
      contentType: multerS3.AUTO_CONTENT_TYPE,
      key: function(req, file, cb) {
          cb(null, `${Date.now().toString()}${file.originalname}`);
      },
      fileFilter: (req, file, cb) => {
            const isValid = !!MIME_TYPE_MAP[file.mimetype]
            let error = isValid ? null : new Error('Invalid mime type!')
            cb(error, isValid);
          }
  }),
});

module.exports = fileUpload;