์ด๋ฏธ์ง๋ฅผ ์
๋ก๋ํ๋ ๊ธฐ๋ฅ์ ๋๋ถ๋ถ์ ์๋น์ค์์ ํ์์
๋๋ค.
์ฌ์ฉ์ ํ๋กํ, ๊ฒ์๊ธ ์ธ๋ค์ผ, ์ฝํ
์ธ ๋ด ์ฒจ๋ถ ์ด๋ฏธ์ง๊น์ง.
์ฒ์์ ๋ฌธ์ ์์ด ๋ณด์ด์ง๋ง,
โ๊ฐ์ ์ด๋ฏธ์ง๊ฐ ์ฌ๋ฌ ๋ฒ ์
๋ก๋๋๋ค๋ฉด?โ
ํนํ S3๋ ์ ์ก๋ + ์ ์ฅ๋ ๋ชจ๋ ๊ณผ๊ธ๋๊ธฐ ๋๋ฌธ์
๊ฐ์ ์ด๋ฏธ์ง๋ฅผ ์ค๋ณต์ผ๋ก ์ฌ๋ฆด์๋ก ์๋น์ค ์ ์ฒด ๋น์ฉ์ด ๊ธฐํ๊ธ์์ ์ผ๋ก ์ฌ๋ผ๊ฐ๋๋ค.
๋จ์ํ filename
์ผ๋ก ํ๋จํ๊ธฐ์ ์ํํฉ๋๋ค.
์ฌ์ฉ์๋ ๊ฐ์ ์ด๋ฏธ์ง๋ฅผ ์ด๋ฆ๋ง ๋ค๋ฅด๊ฒ ์ฌ๋ฆด ์๋ ์๊ณ ,
๊ฐ์ ์ด๋ฆ์ ์์ ํ ๋ค๋ฅธ ์ด๋ฏธ์ง์ผ ์๋ ์์ต๋๋ค.
๊ทธ๋์ ํ์ํ ๊ฑด?
โ ๊ฐ์ฅ ์์ ์ ์ด๊ณ ํจ์จ์ ์ธ ๋ฐฉ์์ด ๋ฐ๋ก
โ ์ด๋ฏธ์ง๋ฅผ ํด์๊ฐ์ผ๋ก ๋ณํํ๋ ๋ฐฉ๋ฒ์
๋๋ค.
HeadObject
๋ก ํ์ธ์ด ๋ฐฉ์์ ๊ฐ์ฅ ํฐ ์ฅ์ ์:
import crypto from 'crypto';
import { S3Client, HeadObjectCommand, PutObjectCommand } from '@aws-sdk/client-s3';
const s3 = new S3Client({
region: 'ap-northeast-2',
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY!,
secretAccessKey: process.env.AWS_SECRET_KEY!,
},
});
const BUCKET_NAME = 'your-bucket-name';
// 1. ์ด๋ฏธ์ง ํด์ ์์ฑ
const getImageHash = async (buffer: Buffer): Promise<string> => {
return crypto.createHash('sha256').update(buffer).digest('hex');
};
// 2. S3์ ํด๋น ์ด๋ฏธ์ง ์กด์ฌ ์ฌ๋ถ ํ์ธ
const checkIfImageExists = async (hash: string): Promise<boolean> => {
try {
await s3.send(new HeadObjectCommand({
Bucket: BUCKET_NAME,
Key: `images/${hash}.jpg`,
}));
return true;
} catch (e) {
return false;
}
};
// 3. ์ต์ข
์
๋ก๋ ํจ์
const uploadImageIfNeeded = async (buffer: Buffer): Promise<string> => {
const hash = await getImageHash(buffer);
const key = `images/${hash}.jpg`;
const exists = await checkIfImageExists(hash);
if (exists) {
console.log(`โ
์ค๋ณต ์ด๋ฏธ์ง์
๋๋ค. ์
๋ก๋ ์๋ต โ ${key}`);
return key;
}
await s3.send(new PutObjectCommand({
Bucket: BUCKET_NAME,
Key: key,
Body: buffer,
ContentType: 'image/jpeg',
}));
console.log(`๐ค ์ด๋ฏธ์ง ์
๋ก๋ ์๋ฃ โ ${key}`);
return key;
};
SHA-256์ ์ฌ์ฉํ๋ค๋ฉด ์ฌ์ค์ ์ถฉ๋์ ๊ฑฑ์ ํ์ง ์์๋ ๋ฉ๋๋ค.
์ ์ธ๊ณ ์ธํฐ๋ท์์ ์ ํต๋๋ ์์ต ๊ฐ ์ด๋ฏธ์ง ์ค,
์ถฉ๋ ์ผ์ด์ค๋ ๋ฌด์ํด๋ ๋ ์์ค์
๋๋ค.
โ๏ธ ๊ถ์ฅํฉ๋๋ค.
์๋ํ๋ฉด ๊ฐ์ ๋ด์ฉ์ด๋๋ผ๋ ํฌ๋งท์ด ๋ค๋ฅด๋ฉด ๋ฐ์ดํธ๋ ๋ฌ๋ผ์ง๊ธฐ ๋๋ฌธ์
๋๋ค.
โ images/{hash}.jpg
, images/{hash}.png
๋ฑ ํ์ฅ์ ๊ธฐ๋ฐ์ผ๋ก ๋ถ๊ธฐํ์ธ์.
ํด๋ผ์ด์ธํธ์์ ์ฒ๋ฆฌํด๋ ์ข์ง๋ง,
๋ณด์์ ๊ณ ๋ คํ๋ฉด ์๋ฒ๋จ์์ ํด์ + ์กด์ฌ ์ฌ๋ถ ํ๋จ์ ์ํํ๋ ๊ฒ ๋ ์์ ํฉ๋๋ค.
S3๋ prefix๊ฐ ๋น์ทํ ํ์ผ์ด ๋ง์ผ๋ฉด ์ฑ๋ฅ ์ ํ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
images/{hash.slice(0,2)}/{hash}.jpg
images/ab/ab123456....jpg
์ฌ์ํด ๋ณด์ผ ์ ์๋ ์ด๋ฏธ์ง ์
๋ก๋ ํ ์ค์ด
์๋น์ค ๋น์ฉ๊ณผ ์ฌ์ฉ์ ๊ฒฝํ์ ์ผ๋ง๋ ํฐ ์ํฅ์ ๋ฏธ์น๋์ง ๋๋ผ์
จ๋์?
์ด๋ฒ ๊ธ์์ ์๊ฐํ ๋ฐฉ์์
๊ฐ๋จํ์ง๋ง ๋งค์ฐ ์ค์ฉ์ ์ด๋ฉฐ,
๋ชจ๋ ์ด๋ฏธ์ง ์
๋ก๋ ์์คํ
์ ์ฝ๊ฒ ์ ์ฉ ๊ฐ๋ฅํ ํจํด์
๋๋ค.
๋งํฌ ๋๋ผํผ๋ ๋จ์ํ ์ ์ฅ ๋๊ตฌ๊ฐ ์๋๋๋ค.
๋งํฌ๋ฅผ ์ ๋ฆฌํ๊ณ , ๋ค์ ๊บผ๋ด๋ณด๋ ์ต๊ด์ ๋๋ ์๋น์ค์
๋๋ค.
โข ๐ ๋น ๋ฅด๊ณ ์ง๊ด์ ์ธ ๋งํฌ ์ ์ฅ
โข ๐ ํด๋๋ณ๋ก ์์ ๋กญ๊ฒ ์ ๋ฆฌ
โข ๐ฌ ๋งํฌ ๊ณต์ ๊น์ง ํ ๋ฒ์
โข โก OG ์ด๋ฏธ์ง/์ ๋ชฉ ์๋ ์ถ์ถ
๐ ์ง๊ธ ๋ฐ๋ก ๋ฒ ํ ๋ฒ์ ์ ์ฒดํํด๋ณด์ธ์!
๐ ๋งํฌ ๋๋ผํผ ๋ฒ ํ ์ฒดํํ๋ฌ ๊ฐ๊ธฐ
โธป
์นด์นด์คํก ์ฑ๋์ ์ถ๊ฐํ์๋ฉด
์
๋ฐ์ดํธ ์์, ๊ธฐ๋ฅ ๊ฟํ, ์ด๋ฒคํธ ๋ฑ์ ๊ฐ์ฅ ๋น ๋ฅด๊ฒ ๋ฐ์๋ณด์ค ์ ์์ต๋๋ค.
๊ธ ์ฌ๋ฏธ์๊ฒ ์ ์ฝ์์ต๋๋ค!
๋ง์ฝ ๋ ๋ช ์ ์ฌ์ฉ์๊ฐ ๋์ผํ ์ด๋ฏธ์ง๋ฅผ ์ ๋ก๋ํ๊ณ , ๋ ์ค ํ ๋ช ์ด ์ด๋ฏธ์ง๋ฅผ ์ญ์ ํ๋ ์ผ์ด ๋ฐ์ํ๋ค๋ฉด ์ด๋ค ์์ผ๋ก ์ฒ๋ฆฌํ์๋์?