AWS s3로 파일 업로드

|

AWS s3로 파일 업로드

aws s3란?

  • S3란 Simple Storage Service의 약자로 쉽게말해 파일을 저장하는 저장소

aws s3 버킷 생성 및 id와 key얻기

npm i aws-sdk multer-s3
  • 버킷 생성

  • 버킷을 생성하면 엑세스가 퍼블릭으로 되있지않을텐데 왼쪽 메뉴에서 퍼블릭계정권한 탭에서 해제하여 퍼블릭으로 바꿔주면된다.

  • 이후 aws 서비스 탭에서 IAM을 눌러 사용자추가를 해준다

    • 사용자 추가를 할때 맨 아래 AWS 액세스 유형 방식에서 프로그래밍 방식 액세스를 체크해준후 다음 탭 클릭
    • (액세스 방식을 사용할것이기 때문)
  • 권한 설정 페이지에서 기존 정책 직접 연결을 눌러 S3를 검색,AmazonS3FullAccess 체크후 다음 탭 클릭후 한번 더 다음 탭 클릭후 사용자 만들기 탭 클릭

  • 이후 access key ID 와 Secret access key가 보여지는 페이지가 나오는데, 이 화면을 떠나면 더이상 여기에 접근할 수 가없기때문에 따로 적어줘야한다.

aws s3에 Multer로 파일 업로드하기

기존 multer를 활용한 코드에서 multer-s3로 바꿔준다. 몇몇의 수정사항이있으니 기존코드와 수정 코드 둘다 올려놓겠다.

기존 multer를 활용한 코드

const multer = require('multer');

//=================================
//             (게시글이미지업로드)
//=================================
var multerImage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, 'uploads/images');
  },
  filename: function (req, file, cb) {
    cb(null, `${Date.now()}_${file.originalname}`);
  },
});
//=================================
//             (프로필이미지업로드)
//=================================
var storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, 'uploads/avatar');
  },
  filename: function (req, file, cb) {
    cb(null, `${Date.now()}_${file.originalname}`);
  },
});

var imageUpload = multer({ storage: multerImage }).single('file');

var avatarUpload = multer({ storage: storage }).single('file');

// module.exports = upload;
exports.avatarUpload = avatarUpload;
exports.imageUpload = imageUpload;

수정된 multer-s3 코드

  • server/middleware/upload
const multer = require('multer');
const multerS3 = require('multer-s3');
const aws = require('aws-sdk');

//=================================
//             (게시글이미지업로드)
//=================================

const s3 = new aws.S3({
  accessKeyId: process.env.AWS_KEY,
  secretAccessKey: process.env.AWS_PRIVATE_KEY,
});

var imageUpload = multer({
  storage: multerS3({
    s3: s3,
    acl: 'public-read',
    bucket: 'gongcha/uploadImage',
    contentType: multerS3.AUTO_CONTENT_TYPE,
    metadata: function (req, file, cb) {
      cb(null, { fileName: file.fieldname });
    },
    key: function (req, file, cb) {
      var filename = file.originalname;

      var ext = file.mimetype.split('/')[1];
      if (!['png', 'jpg', 'jpeg', 'gif', 'bmp'].includes(ext)) {
        return cb(new Error('Only images are allowed'));
      }

      cb(null, Date.now().toString() + filename);
    },
  }),
}).single('file');

var avatarUpload = multer({
  storage: multerS3({
    s3: s3,
    acl: 'public-read-write',
    bucket: 'gongcha/avatarImage',
    contentType: multerS3.AUTO_CONTENT_TYPE,
    metadata: function (req, file, cb) {
      cb(null, { fileName: file.fieldname });
    },
    key: function (req, file, cb) {
      var filename = file.originalname;
      var ext = file.mimetype.split('/')[1];
      if (!['png', 'jpg', 'jpeg', 'gif', 'bmp'].includes(ext)) {
        return cb(new Error('Only images are allowed'));
      }

      cb(null, Date.now().toString() + filename);
    },
  }),
}).single('file');

// module.exports = upload;
exports.avatarUpload = avatarUpload;
exports.imageUpload = imageUpload;
exports.s3 = s3;
  • server/routes/api/users.js
    • 기존에 file.path였지만,file.location로 변경해줘야 받을 수 있다.
// @route   POST api/users/edit/avatar (프로필 이미지 편집)
// @desc    AvatarChange user
// @access  Private
router.post('/edit/avatar', async (req, res) => {
  // 프론트 에서 가져온 이미지를 저장을 해준다.
  upload.avatarUpload(req, res, (err) => {
    if (err) {
      return res.json({ success: false, err });
    }
    if (!req.file) return res.send('Please upload a file');

    return res.json({
      success: true,
      filePath: res.req.file.location,
      fileName: res.req.file.originalname,
    });
  });
});
  • 이후 프론트에서 이미지를 불러올때 기존의 코드는가

    <img src={`http://localhost:5000/${user.avatar}`} alt='userAvatar' />
    

    이랬다면, 이렇게 바꿔줘야한다.

<img src={user.avatar} alt='userAvatar' />

s3에 파일 업로드된거 삭제 해주기

☆★☆★ 파일명 꼭 영어로 해주기☆★☆★
s3는 한글명으로하면 에러난다고함 그리고 작동안함
실제로 이 문제 때문에 꼬박 하루 고생했음

// @route   DELETE api/posts/:id
// @desc    게시글 지우기
// @access  Private
router.delete('/:id', auth, async (req, res) => {
  try {
    const post = await Post.findById(req.params.id);
    const user = await User.findById(req.user.id).select('-password');

    if (!post) {
      return res.status(404).json({ msg: '게시글이 없습니다.' });
    }

    // aws s3 버킷에서 파일 삭제
    const url = post.image.split('/'); // post에 저장된 image를 가져옴
    const delFileName = url[url.length - 1];

    const params = {
      Bucket: 'gongcha',
      Key: `uploadImage/${delFileName}`,
    };

    upload.s3.deleteObject(params, function (err, data) {
      console.log(params);

      if (err) {
        console.log('aws image delete error');
        console.log(err, err.stack);
        return;
      } else {
        console.log('aws image delete success' + data);
      }
    });

    // check user
    if (post.user.toString() !== req.user.id) {
      return res.status(401).json({ msg: '게시글을 작성한 유저가 아닙니다.' });
    }
    const userPost = user.posts.filter(
      (post) => post._id.toString() !== req.params.id
    );
    // Get remove index
    const removeIndex = user.posts
      .map((post) => post._id.toString())
      .indexOf(req.user.id);

    user.posts.splice(removeIndex, 1);

    await user.save();
    await post.remove();

    res.json({ msg: '게시글 삭제 완료' });
  } catch (err) {
    if (err.kind === 'ObjectId') {
      return res.status(404).json({ msg: '게시글을 찾을 수 없습니다.' });
    }
    res.status(500).send('Server Error');
  }
});