AWS
S3 presignedUrl 생성 , presignedUrl이용해서 S3,DB에 이미지저장
신입주니어개발자
2022. 3. 10. 10:17

서버에서 직접 multipart를 받아 S3 버킷에 업로드하면 서버쪽에서 multipart 파일을 쥐고 있어야 하는 둥 리소스 낭비가 크므로 S3에 접근할 수 있는 Presigned url을 생성하여 클라이언트가 직접 업로드하게 한다.
https://docs.aws.amazon.com/ko_kr/AmazonS3/latest/dev/PresignedUrlUploadObjectJavaSDK.html
presigned url 이란 AWS S3 버킷에 바로 파일을 업로드 할 수 있는 URL을 말한다.
생성 및 사용
const aws = require("aws-sdk")
const {AWS_ACCESS_KEY , AWS_SECRET_KEY} = process.env
const s3 = new aws.S3({
accessKeyId:AWS_ACCESS_KEY,
secretAccessKey:AWS_SECRET_KEY
})
const getSignedUrl = ({key})=>{
return new Promise((resolve,reject)=>{
s3.createPresignedPost({
Bucket:"image-upload-tutorial",
Fields:{
key
},
Expires: 300, //만료기간에 업로드를 하지않으면 url날려버림
Conditions:[
["content-length-range",0,0*50*1000*1000],
["starts-with","$Content-Type","image/"]//이미지파일만 받게 설정
]
},(err,data)=>{
if(err) throw reject(err)
resolve(data)
})
})
}
module.exports = {s3,getSignedUrl}
aws.js
const {s3,getSignedUrl} = require("../aws")
const {v4: uuid} = require('uuid')
const mime = require("mime-types");
imageRouter.post("/presigned",async(req,res)=>{
try{
if(!req.user) throw new Error("권한이 없습니다")//로그인x
const {contentTypes} = req.body
if(!Array.isArray(contentTypes)) throw new Error("invalid contentTypes")
//이미지 여러개 올릴경우 presignedUrl을 여러개만들어 한번에 보내주는게 좋음
const preSignedData = await Promise.all(contentTypes.map(async(contentType) =>{
const imageKey = `${uuid()}.${mime.extension(contentType)}`
const key = `raw/${imageKey}`
const presigned = await getSignedUrl({key})
return {imageKey,presigned}
}))
return res.json(preSignedData)
}catch(err){
res.status(400).json({message:err.message})//400 :유저잘못입력 , 500:서버오류
console.log(err)
}
})
imageRouter.get("/:imageId" , async function(req,res){
try{
const {imageId} = req.params;
if(!mongoose.isValidObjectId(imageId)) throw new Error("올바르지않은 id입니다")
const image = await Image.findOne({_id:imageId})
if(!image) throw new Error("존재하지 않습니다")
res.json(image);
}catch(err){
res.status(400).json({message:err.message})
console.log(err)
}
});
imageRouter.js
const onSubmitV2 = async (e) => {
e.preventDefault();
try {
setIsLoading(true);
const presignedData = await axios.post("/images/presigned", {
contentTypes: [...files].map((file) => file.type),
});
await Promise.all(
[...files].map((file, index) => {
const { presigned } = presignedData.data[index];
const formData = new FormData();
for (const key in presigned.fields) {
formData.append(key, presigned.fields[key]);
}
formData.append("Content-Type", file.type);
formData.append("file", file);
return axios.post(presigned.url, formData);
})
);
uploadForm.js(프론트)
참고:미리 서명된 URL을 사용하여 객체 업로드 - Amazon Simple Storage Service
미리 서명된 URL을 사용하여 객체 업로드 - Amazon Simple Storage Service
미리 서명된 URL을 사용하여 객체 업로드 미리 서명된 URL의 생성자가 해당 객체에 대한 액세스 권한을 보유할 경우, 미리 서명된 URL은 URL에서 식별된 객체에 대한 액세스를 부여합니다. 즉, 객체
docs.aws.amazon.com