프로젝트 진행 중 이미지를 사용하기 위해 AWS S3를 사용했다. 내가 AWS S3와 multer를 사용한 방법에 대해 기록해 보려고 한다.
어디서나 원하는 양의 데이터를 검색할 수 있도록 구축된 객체 스토리지
AWS 공식 홈페이지에서 확인할 수 있는 문구이다. 나는 이미지를 사용하기 위해 S3를 사용했는데, 이미지 이외에도 다양한 객체를 넣을 수 있다. 중요한 것은 버킷인데, 이곳에 원하는 데이터를 넣고 관리하며 사용할 수 있다.
만약 내가 피카츄 이미지를 버킷에 업로드한다고 치자. picka.jpg를 버킷에 담게되면 https://DOC-EXAMPLE-BUCKET.s3.us-west-2.amazonaws.com/photos/picka.jpg와 같은 형태의 url을 얻을 수 있고, 내가 원하는 곳에 url을 통해 이미지를 사용할 수 있다.
AWS S3를 사용하면서 이미지를 백업해 놓을 수 있고, 버킷에 저장해놓고 사용하기 때문에 삭제되지 않는 이상 혹시라도 이미지가 깨지는 걱정은 하지 않아도 된다는 점..!
multer는 multipart/form-data를 다루기 위한 node.js의 미들웨어이며, 이는 주로 파일을 업로드할 때 사용한다. multer-s3는 S3에 파일을 업로드 하도록 만들어주는 모듈이다. 다음과 같은 명령어로 설치할 수 있다.
npm install --save multer multer-s3
1. env 파일에 s3 키 작성하기
S3_ACCESS_KEY = "AWS에서 발급받은 액세스 키"
S3_SECRET_KEY = "AWS에서 발급받은 시크릿 키"
BUCKET_NAME = "버킷 이름"
나는 보안상 env파일에 적어놓고 사용했다.
2. S3 미들웨어 파일 작성하기
처음에는 이전 프로젝트에서 나 말고 다른 분이 s3사용한 코드가 있어서 참고하고 작성했다.
const s3 = new AWS.S3({
accessKeyId: process.env.AWS_ACCESSKEYID,
secretAccessKey: process.env.AWS_SECRETKEY,
});
const upload = multer({
storage: multerS3({
s3, // Type 'S3' is missing the following properties from type 'S3Client': destroy, middlewareStack, sendts(2739)
bucket: process.env.BUCKET_NAME as string,
contentType: multerS3.AUTO_CONTENT_TYPE,
key: function (req, file, cb) {
const fileId = shortId.generate();
const type = file.mimetype.split('/')[1];
const fileName = `${fileId}.${type}`;
cb(null, fileName);
},
acl: 'public-read-write',
}),
});
그런데 주석을 작성한 부분에서 에러가 떴다. 이전에는 잘만 동작했는데.. 여기서 멘붕이 왔다. 생각해보니까 이전 프로젝트와 다른 점은 JS와 TS밖에 없는데, TS로 인해 문제가 생긴 것이다. 열심히 구글링을 한 결과, 한 스택오버플로우 글을 찾을 수 있었다.
How to set credentials in AWS SDK v3 JavaScript?
아하.. S3Client객체의 속성인 credentials에 키값을 넣어줘야 하는구나. 그렇게 문제를 해결할 수 있었다.
import multer from 'multer';
import multerS3 from 'multer-s3';
import shortId from 'shortid';
import { S3Client } from '@aws-sdk/client-s3';
const upload = multer({
storage: multerS3({
s3: new S3Client({
credentials: {
accessKeyId: process.env.S3_ACCESS_KEY as string,
secretAccessKey: process.env.S3_SECRET_KEY as string,
},
region: 'ap-northeast-2',
}),
bucket: process.env.BUCKET_NAME as string,
contentType: multerS3.AUTO_CONTENT_TYPE,
key: function (req, file, cb) {
const fileId = shortId.generate();
const type = file.mimetype.split('/')[1];
const fileName = `${fileId}.${type}`;
cb(null, fileName);
},
acl: 'public-read-write',
}),
});
파일명은 겹치지 않도록 shortId를 사용했다. 이제 이 upload 미들웨어를 통해 내가 만든 AWS S3 버킷에 이미지를 저장할 수 있다.
app.post('/test', upload.single('image'), async (req, res, next) => {
try {
res.status(200).json({ result: 'ok' });
} catch (error) {
next(error);
}
});
다음과 같이 테스트용 라우터 코드를 작성하고, localhost:5000/test에 post요청을 보낸다.
여기서 주의할 점 두 가지가 있다.
첫 번째는 key값은 위에서 작성한 라우터의 미들웨어(upload.single('image')에 작성한 값과 동일해야 한다.
두 번째로 form-data로 전송해야 한다.
위의 조건이 만족한다면, 버킷에 내가 전송한 이미지가 업로드 되어있는 모습을 확인할 수 있다!
감사합니다. 덕분에 multerS3 문제 해결하고 가요 :)