Node
에서 Multer
라이브러리를 통해 이미지를 받아 그걸 다시 S3 버킷에 저장해주는 식으로 진행을 하였다.Node
에서 이미지 처리를 담당한다는거 자체가 서버에무리가 많이 갈 것 같았다.Pre-Signed url
이란걸 사용하면 보안적으로도 안전하게 프론트에서 바로 S3 버킷에 이미지를 저장시킬 수 있다는 걸 듣고 적용해보았다.AWS 공식 문서에서는 아래와 같이 말해준다.
미리 서명된 URL의 생성자가 해당 객체에 대한 액세스 권한을 보유할 경우, 미리 서명된 URL은 URL에서 식별된 객체에 대한 액세스를 부여합니다.
즉, 객체를 업로드하기 위해 미리 서명된 URL을 수신하는 경우, 미리 서명된 URL의 생성자가 해당 객체를 업로드하는 데 필요한 권한을 보유하는 경우에만 객체를 업로드할 수 있습니다.
즉 사용자에게 미리 서명된 URL 을 제공하여 이를 이용하여 S3 버킷
에 접근 권한을 설정해줄 수 있다.
이때 미리 서명된 URL은 URL을 아는 모든 사람에게 Amazon S3
버킷에 대한 액세스 권한을 부여하므로 적절하게 접근 권한 및 만료시간을 설정해주어야 한다.
import AWS from "aws-sdk";
AWS.config.update({
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
region: process.env.AWS_REGION,
signatureVersion: "v4",
});
const s3 = new AWS.S3();
const myBucket = process.env.BUCKET_NAME;
const signedUrlExpireSeconds = 60 * 5;
export default function createUrl(fileName) {
const url = s3.getSignedUrl("putObject", {
Bucket: myBucket,
Key: fileName,
Expires: signedUrlExpireSeconds,
ContentType: "image/*",
});
return url;
}
위 코드는 Pre-Sign URL
을 생성해주는 코드이다.
위 AWS.config.update
는 AWS 설정에 사용자 인증을 받는 것 이고, 아래 AWS s3
부분은 그 사용자의 S3에 대해 접근한다는걸 알려준다.
이때 createUrl
함수안에 getSignedUrl
을 통해 Pre-Sign URL
만들어주고 이 안에 권한 설정 및 필요한 인자 값들을 넣어준다.
putObject
는 이미지를 전송하는 권한
Bucket
은 버킷의 이름, Key
는 파일의 이름 [ 유니크한 값 ], Expires
는 URL의 유효시간이다.
uploadRouter.get('/:file', (req, res, next) => {
const { file } = req.params;
const fileName = Date.now() + file;
try {
const url = createUrl(`diary/${fileName}`);
} catch (error) {
next(error);
}
const imageUrl = `https://ai-project-last.s3.ap-northeast-2.amazonaws.com/diary/${fileName}`;
const body = {
success: true,
url,
imageUrl,
};
res.status(201).json(body);
});
path로 파일의 이름을 받은 후, 유니크한 값으로 만들기 위해 현재 시간을 더한 문자열로 만들어준다.
그 후 위에서 만든 createUrl
을 통해 만든 파일 이름을 보낸 후, 그것에 해당하는 Pre-Sign URL
을 발급 받아 Front에 그 값을 전달해준다.
그 전에 Multer와 Node를 사용해 이미지를 처리할 때 보다 훨씬 빠른 속도로 처리가 가능해졌다.
또한, 서버에 이미지가 오지 않기 때문에 서버에 대한 부담도 줄일 수 있었다.
백엔드 개발자는 기능 구현에만 신경쓰는 것이 아닌 서버에 대한 최적화, 보안 등을 모두 다 생각해야 한다고 배웠을 땐 기능만 잘 구현하면 되는거 아닌가..?
라고 생각했다.
하지만 위 방법을 통해 같은 기능이지만 완전히 다른 방향으로 구현하고, 사용하는 방법 또한 완전히 다르지만 그로인한 성능차이 등을 느끼며 정말 백엔드 개발자는 지식에 따라 엄청난 차이가 생기는구나 생각을 했다.
다음번 프로젝트 또한 기능을 구현할 때 더 좋은 방법, 서버에 대한 무리를 더 줄이는 방법 등등을 더 학습하고 구현해봐야겠다!