π‘Β S3 λ²ν·μμ μ¬μ©μμκ² νμΌμ λ°ννκ±°λ μ¬μ©μκ° νμΌμ S3 λ²ν·μ μμ νκ² μ λ‘λ ν΄μΌνλ μν©μμ μ£Όλ‘ μ¬μ©
β
Β μ¬μ©μμκ² λ―Έλ¦¬ μλͺ
λ URLμ μ 곡νμ¬ μ΄λ₯Ό μ΄μ©νμ¬ S3 λ²ν·μ μ κ·Ό κΆνμ μ€μ ν΄ μ€ μ μμ
β Β μ΄λ, 미리 μλͺ λ URLμ URLμ μλ λͺ¨λ μ¬λμκ² Amazon S3 λ²ν·μ λν μ‘μΈμ€ κΆνμ λΆμ¬νλ―λ‘ μ μ νκ² μ κ·Ό κΆν λ° λ§λ£ μκ°μ μ€μ ν΄μ£Όμ΄μΌ νλ€.
signedHeaders ν¬ν¨: μλͺ
μ μμ±ν λ, μ νμ μΌλ‘ signedHeaders λ§€κ°λ³μλ₯Ό ν¬ν¨μμΌ νΉμ HTTP ν€λλ₯Ό μμ²μ μΌλΆλ‘ μ§μ ν©λλ€. μ΄λ μλͺ
μ μΌλΆκ° λλ©°, μμ² κ²μ¦ μ νμΈλ©λλ€.β Β νΉμ 리μμ€μ λν΄ λ―Έλ¦¬ μλͺ λ URLμ μμ±νμ¬, μ΄λ₯Ό ν΄λΌμ΄μΈνΈλ‘ λ°ννκΈ° μν μ νλ μ격μ¦λͺ μ΄ μλ μ μ© λ°±μλ μλΉμ€λ₯Ό 보μ
λλΆλΆ AWSμ SDK κΈ°λ₯μ μ¬μ©νμ¬ κ΅¬μ±, μμ± λλ€.
β Β S3κ° μ νμ signedHeaders λ§€κ°λ³μλ₯Ό κ³μ°μ ν¬ν¨νκ³ μλͺ μ΄ μ ν¨νμ§, λ§ν¬κ° μμ§ λ§λ£λμ§ μμλμ§ νμΈνλ κ²μ ν¬ν¨νμ¬ μ§μ λ μ격μ¦λͺ μ λν΄ λμΌν μλͺ μ κ³μ°νλ €κ³ μλνλ€λ κ².
μ²μμλ getμμ²μ΄ λ§λ€κ³ νλ¨νμ¬ getμμ²μΌλ‘ μ½λλ₯Ό μμ±νλ€. κ·Έλ¦¬κ³ μμλ‘ μ°Ύμλ³Έ μ½λ λͺ¨λ presigned urlμ getμΌλ‘ μμ±νκΈ° λλ¬Έ.
νμ§λ§, ν΄λΌμ΄μΈνΈ λ¨μμ μ΅λ 10κ°μ νμΌλͺ μ 보λ΄μ£Όμ΄μΌνκΈ° λλ¬Έμ, queryλ‘ νκΈ° μ΄λ €μΈ κ² κ°μλ€. κ·Έλμ κ²μν΄λ³΄λ, presigned postλΌλ κ²μ΄ μμλ€. gptμκ² μμΈν λ¬Όμ΄λ³΄μ!

μμ½νμλ©΄ presigned urlμ λ€μ΄λ‘λμ μ¬μ©λκ³ , presigned postλ μ
λ‘λμ μ¬μ©λλ€λ κ²!
const express = require('express');
const router = express.Router();
const {
generateUploadPresignedUrls,
generateDownDelPresignedUrls,
parseFileType,
parseFileName,
} = require('../utils/presigned_file');
const env = process.env;
objectKeys = [];
// ν΄λΌμ΄μΈνΈμκ² putObject presignedURLμ λ°ν
async function postPresigned(req, res, next) {
const { files, inspection_area_id, size, label } = req.body;
const fileType = parseFileType(files);
const bucketName = env.BUCKET;
console.log(files, fileType, inspection_area_id);
try {
// μ
λ‘λλ₯Ό μν presignedURL μμ±
const presignedUrl = await generateUploadPresignedUrls(
files,
fileType,
bucketName,
'putObject'
);
objectKeys = presignedUrl.map((item) => item.key);
res.status(200).send({
data: { presignedUrl },
});
console.log(objectKeys);
} catch (error) {
console.error('Failed to generate presigned URL', error);
res.status(500).send('Failed to generate presigned URL');
}
}
module.exports.postPresigned = postPresigned;
// ν΄λΌμ΄μΈνΈμκ² getObject presignedURLμ λ°ν
async function getPresigned(req, res, next) {
const { files, inspection_area_id, size, label } = req.body;
//bodyλ‘ νμΌλͺ
κ³Ό MIME type
const fileType = parseFileType(files); //db μ‘°ν
const bucketName = env.BUCKET;
console.log(files, fileType, inspection_area_id);
try {
const presignedUrl = await generateDownDelPresignedUrls(
objectKeys,
fileType,
bucketName,
'getObject'
);
res.status(200).send({
data: { presignedUrl },
});
console.log('Success to generate presigned URL');
} catch (error) {
console.error('Failed to generate presigned URL', error);
res.status(500).send('Failed to generate presigned URL');
}
}
module.exports.getPresigned = getPresigned;
// ν΄λΌμ΄μΈνΈμκ² deleteObject presignedURLμ λ°ν
async function deletePresigned(req, res, next) {
const { files, inspection_area_id, size, label } = req.body;
//bodyλ‘ νμΌλͺ
κ³Ό MIME type
console.log(objectKeys);
const fileType = parseFileType(files); //db μ‘°ν
const bucketName = env.BUCKET;
try {
// μ
λ‘λλ₯Ό μν presignedURL μμ±
const presignedUrl = await generateDownDelPresignedUrls(
objectKeys,
fileType,
bucketName,
'deleteObject'
);
res.status(200).send({
data: { presignedUrl },
});
console.log('Success to generate presigned URL');
} catch (error) {
console.error('Failed to generate presigned URL', error);
res.status(500).send('Failed to generate presigned URL');
}
}
module.exports.deletePresigned = deletePresigned;
const {
S3Client,
GetObjectCommand,
PutObjectCommand,
DeleteObjectCommand,
} = require('@aws-sdk/client-s3');
const { getSignedUrl } = require('@aws-sdk/s3-request-presigner');
const env = process.env;
// AWS μ 보
const s3Client = new S3Client({
region: 'ap-northeast-2',
credentials: {
accessKeyId: env.AWS_ACCESS_KEY_ID,
secretAccessKey: env.AWS_SECRET_ACCESS_KEY,
},
});
function parseFileName(files) {
return files.map((file) => {
const dotIndex = file.lastIndexOf('.');
const fileName = file.substring(0, dotIndex);
return fileName;
});
}
module.exports.parseFileName = parseFileName;
function parseFileType(files) {
return files.map((file) => {
const dotIndex = file.lastIndexOf('.');
const fileType = file.substring(dotIndex);
switch (fileType) {
case '.pdf':
return 'application/pdf';
case '.docx':
return 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
case '.xlsx':
return 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
case '.hwp':
return 'application/hwp';
case '.txt':
return 'text/plain';
case '.zip':
return 'application/zip';
case '.mp4':
return 'video/mp4';
case '.heif':
return 'image/heif';
case '.jpeg':
return 'image/jpeg';
case '.png':
return 'image/png ';
default:
return 'application/octet-stream'; // κΈ°λ³Έκ°μΌλ‘, μλ €μ§μ§ μμ νμΌ νμ
μ²λ¦¬
}
});
}
module.exports.parseFileType = parseFileType;
// μ¬λ¬κ°μ pre-signed url μμ±
async function generateUploadPresignedUrls(files, fileTypes, bucketName, operation) {
return Promise.all(
files.map(async (file, index) => {
const fileType = fileTypes[index];
const objectKey = `presigned/${file.substring(
0,
file.indexOf('.')
)}_${Date.now()}.${file.substring(file.indexOf('.') + 1)}`;
// κ°λ³ presignedurlμ μμ±νκΈ° μν ν¨μ νΈμΆ
const presignedUrl = await generatePresignedUrl(
bucketName,
fileType,
objectKey,
operation
);
return {
url: presignedUrl,
bucket: bucketName,
key: objectKey,
};
})
);
}
async function generateDownDelPresignedUrls(
objectKeys,
fileTypes,
bucketName,
operation
) {
return Promise.all(
objectKeys.map(async (objectKey, index) => {
const fileType = fileTypes[index];
// κ°λ³ presignedurlμ μμ±νκΈ° μν ν¨μ νΈμΆ
const presignedUrl = await generatePresignedUrl(
bucketName,
fileType,
objectKey,
operation
);
return {
url: presignedUrl,
bucket: bucketName,
key: objectKey,
};
})
);
}
// κ°λ³ νμΌμ λν pre-signed url μμ± (put, get, delete)
async function generatePresignedUrl(bucketName, fileType, objectKey, operation) {
let command;
// μ
λ‘λλ₯Ό μν url μμ± μ, command === putObject
if (operation === 'putObject') {
command = new PutObjectCommand({
Bucket: bucketName,
Key: objectKey,
ContentType: fileType,
});
// λ€μ΄λ‘λλ₯Ό μν url μμ± μ, command === getObject
} else if (operation === 'getObject') {
command = new GetObjectCommand({
Bucket: bucketName,
Key: objectKey,
ContentType: fileType,
});
// μμ λ₯Ό μν url μμ± μ, command === delteObject
} else if (operation === 'deleteObject') {
command = new DeleteObjectCommand({
Bucket: bucketName,
Key: objectKey,
ContentType: fileType,
});
}
try {
// μ ν¨μκ° 1μκ° μ€μ (60*60)
const url = await getSignedUrl(s3Client, command, { expiresIn: 60 * 60 });
return url;
} catch (err) {
console.error('Error generating presigned URL', err);
throw err;
}
}
module.exports.generateUploadPresignedUrls = generateUploadPresignedUrls;
module.exports.generateDownDelPresignedUrls = generateDownDelPresignedUrls;