유저 아바타 AWS S3에 저장
서버 하드에 저장하면 서버 재배포 시 새로 생긴 경로는 모조리 삭제되서 초기화된다..
이 문제를 마주하고 처음에는 서버를 재배포 할 때마다 서버에 있는 새로 생긴 폴더를 다 다운받으면 되지 않을까? 하는 생각을 했다.
크롬 확장도구인 Resources Saver를 사용하면 해당 페이지의 개발자 도구-Resources 탭에서 볼 수 있는 모든 파일을 다운해준다.
하지만 이 방법은 서버를 배포하기 전에 항상 내가 수동으로 작업해야하고, 한 번이라도 잊어버리면 모든 유저 이미지를 날릴 수 있는 위험이 있었다.
AWS S3를 사용하기로 마음을 먹는데..
프론트엔드를 시작해서 서버구축도 해보고 NoSQL도 생성해보고 많은 성장을 하고 있지만 AWS라는 단어는 조금 무서웠다.
하지만 요즘은 이미지,동영상 등 파일은 모두 따로 서버를 구축해서 저장하고 DB에는 링크만 저장하는 방법을 주로 사용한다고 한다.
그래서 S3사용법을 찾기 시작했다.
버킷, 정책과 권한 설정. 혼돈의 카오스
여러 블로그들을 찾아봤는데 S3의 버킷을 생성하는 과정부터 정책, 권한 등 설정을 다들 다르게 기술 하고 있었다.
그리고 예전 블로그가 많아서 현재 S3 콘솔의 단계나 UI가 달라서 많이 헤메기도 했다.
그래도 공통적인 사용법을 찾고, 공식 문서에 나와있는대로 설정을 하고 multer가 S3의 버킷에 업로드 할 수 있도록 설정 코드를 작성했다.
import AWS from 'aws-sdk';
import multer from 'multer';
import multerS3 from 'multer-s3';
import dotenv from 'dotenv';
dotenv.config();
const { AWS_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_IDENTITYPOOLID } = process.env;
AWS.config.update({
region: AWS_REGION,
accessKeyId: AWS_ACCESS_KEY_ID,
secretAccessKey: AWS_SECRET_ACCESS_KEY,
credentials: new AWS.CognitoIdentityCredentials({
IdentityPoolId: AWS_IDENTITYPOOLID,
}),
});
const s3 = new AWS.S3();
export const upload = multer({
storage: multerS3({
s3: s3,
bucket: 'sentenceu-avatar', // 버킷 이름
contentType: multerS3.AUTO_CONTENT_TYPE, // 자동을 콘텐츠 타입 세팅
key: function (req, file, cb) {
const ext = file.mimetype.split('/')[1];
if (!['png', 'jpg', 'jpeg', 'gif', 'bmp'].includes(ext)) {
return cb(new Error('Only images are allowed'));
}
cb(null, `${req.params.id}_${Date.now()}_${file.originalname}`);
},
acl: 'public-read-write',
limits: { fileSize: 50 * 1024 }, // 500kb 용량 제한
}),
});
- AWS 환경변수들을 사용 할 수 있도록 dotenv사용
- AWS.config를 사용해 기본 엑세스 키 설정
- multer의 storage를 s3로 설정하고 버킷은 내가 생성한 버킷 이름 설정
- file.mimetype을 이용해 확장자 필터링 설정
- 버킷에 저장할 이름 : 유저id + 현재시간 + 파일이름
- acl : 공용 읽기 쓰기 가능하도록
- limits 500kb 용량제한
위처럼 설정해서 메인 api라우터에서 미들웨어로 사용한다.
router.post('/users/:id/avatar/upload', upload.single('avatar'), async (req, res) => {
const url = req.file.location;
await User.updateOne({ _id: req.params.id }, { $set: { userAvatar: url } })
.then((user) => {
if (!user) return res.status(403).json({ message: 'User not found.' });
return res.status(200).json({ message: 'Upload Success', location: req.file.location });
})
.catch((error) => res.status(500).json({ message: error.message }));
});
미들웨어 upload(multer + s3)를 통과하면 params의 id로 유저를 찾아 아바타의 url을 s3에 저장된 이미지의 링크로 변경해준다.
라고 작성한 대로 바로 될리가 없다! 문제가 한개씩은 있어야지
TypeError: this.client.send is not a function
프론트에서 파일을 업로드하고 post를 보내니 미들웨어에서 에러가 발생했다.
원인은 multer-s3버전과 aws-sdk의 버전 호환에 문제가 있었다.
npm i multer-s3@2.10.0
multer-s3를 2버전으로 설치하여 해결 할 수 있다.
버킷의 객체 접근 권한 문제
처음에 버킷과 사용자 생성하는데에 많은 혼돈이 있다고 하지 않았는가..
CORS 구성부터 버킷 정책까지 multer를 사용해 s3에 파일을 올린 많은 이들의 글을 읽고 설정을 해보았지만 권한이 없다는 문제로 계속 에러가 발생했다.
그때 인파님의 S3에 대해 자세히 정리된 글을 보고 처음부터 다시 생성하고 설정해봤다.
버킷정책(Bucket Policy)까지는 Json으로 설정했지만 접근정책(ACL)에 대한 설정을 빼먹었었다.
ACL을 활성화 하고 모든 사람이 버킷 ACL에 읽기에 대한 권한을 가질 수 있도록 설정을 하니 이미지를 업로드 했을 때 비로소 문제 없이 버킷에 저장되고 링크가 생성됐다.
다사다난했던 AWS S3에 이미지 업로드 성공!