npm i aws-sdk
AWS S3 버킷 생성 및 권한 설정에서 이미지 저장 및 삭제는 권한(IAM 정책
)을 부여했다.
IAM 정책 생성
시 받은 액세스 키(AWS_ACCESS_KEY)
, 시크릿 키(AWS_SECRET_KEY)
와 S3 리전(AWS_REGION)
을 .env
에서 관리한다.
ex)
import aws from 'aws-sdk';
const { AWS_SECRET_KEY, AWS_ACCESS_KEY, AWS_REGION } = process.env;
export const s3 = new aws.S3({
secretAccessKey: AWS_SECRET_KEY,
accessKeyId: AWS_ACCESS_KEY,
region: AWS_REGION,
});
이미지를 저장하는 방법 중에 아래와 두 가지 방법이 있다.
Client
에서 -> Backend
로 이미지 파일을 전송 후 multer-s3
를 이용해 s3에 이미지를 저장하는 방법.
Client
or Backend
에서 PresignedUrl
을 이용해 S3에 이미지를 업로드하는 방법.
createPresignedPost
를 이용해 PresignedUrl
을 생성한다.key
부분은 이미지 저장 경로 및 파일 이름image/<파일 이름>.<파일 확장자>
import aws from 'aws-sdk';
const { AWS_SECRET_KEY, AWS_ACCESS_KEY, AWS_REGION } = process.env;
export const s3 = new aws.S3({
secretAccessKey: AWS_SECRET_KEY,
accessKeyId: AWS_ACCESS_KEY,
region: AWS_REGION,
});
export const getSignedUrl = ({ key }: { key: string }) => {
return new Promise((resolve, reject) => {
s3.createPresignedPost(
{
Bucket: '<your bucket name>',
Fields: {
key, /* ex) image/<파일 이름>.<jpeg or png> */
},
Conditions: [
['content-length-range', 0, 50 * 1000 * 1000],
['starts-with', '$Content-Type', 'image/'],
],
},
(err, data) => {
if (err) reject(err);
resolve(data);
}
);
});
};
getSignedUrl
이용해 생성된 PresignedUrl
하고 imageKey(image/<파일 이름>.<jpeg or png>)
를 응답한다.import express, { Request, Response, NextFunction } from 'express';
import { s3, getSignedUrl } from '../aws';
const router = express.Router();
/* ... */
router.post('/presigned', async (req, res, next) => {
try {
const { contentTypes } = req.body;
if (!Array.isArray(contentTypes)) throw new Error('error');
const presignedData = await Promise.all(
contentTypes.map(async (conteType) => {
const imageKey = `${uuid()}.${mime.extension(conteType)}`;
const key = `image/${imageKey}`;
const presigned = await getSignedUrl({ key });
return { imageKey, presigned };
})
);
res.json(presignedData);
} catch (err) {
next(err);
}
});
/* ... */
export default router;
PresignedUrl
생성하고 응답받은 presignedData(imageKey(이미지 파일 이름), PresignedUrl(업로드 url))
을 이용해 Client
에서 S3에 이미지를 저장한다. const imgContentTypes = imgFile.map((el) => el?.type);
/* presignedUrl 생성하기 */
const res = await request.post('/upload/presigned', {
contentTypes: imgContentTypes,
});
/* s3 이미지 저장 */
await Promise.all(
imgFile.map((file, index) => {
const { presigned } = res.data[index];
const formData = new FormData();
for (const key in presigned.fields) {
formData.append(key, presigned.fields[key]);
}
file && formData.append('Content-Type', file.type);
file && formData.append('file', file);
return axios.post(presigned.url, formData);
})
);
Bucket
부분에 해당 S3 버킷 이름을 적어준다.Key
부분에 버킷에서 삭재할 이미지 경로와 파일 이름을 적어준다. image
폴더에 이미지 저장했기 때문에 Key
부분에 <폴더>/<삭제할 이미지 파일 이름>.<파일 확장자>
를 입력했다.image/<img 파일 이름>.jpeg
ex)
import express, { Request, Response, NextFunction } from 'express';
import { s3, getSignedUrl } from '../aws';
const router = express.Router();
/* ... */
router.delete(
'/image/:id',
async (req: Request, res: Response, next: NextFunction) => {
try {
await s3.deleteObject(
{
Bucket: '<your bucket name>',
Key: `image/${req.params.id}`,
},
(err, data) => {
if (err) throw err;
}
);
res.json({
message: 'success',
});
} catch (err) {
next(err);
}
}
);
/* ... */
export default router;