개인 블로그에 있는 내용 중 project 페이지에서 사용될 이미지는 AWS S3에 저장 후 페이지로 가져오는 방법을 선택해 해당 방법에 대해 정리해보았다.
AWS SDK 사용법
S3 서비스만 필요함으로 @aws-sdk/client-s3를 설치했다.
개별 서비스 클래스를 바로 import 하면 메모리를 절약할 수 있다는 장점이 있다.
npm
https://www.npmjs.com/package/@aws-sdk/client-s3
// 개별 서비스 npm i @aws-sdk/client-s3 const { S3Client } = require("@aws-sdk/client-s3");
AWS Credentials : aws region 및 자격증명 설정
AWS 서비스와 연동하기 위해선 자격증명(Credentials)인 accessKeyId와 secretAccessKey가 필요하다. 해당 키들은 .env에 저장 후 불러온다.
관련글 : https://minsunblog.com/blog/6f019894-87f0-4944-a0b5-fb251a085586
//aws s3 image const credentials = { accessKeyId: AWS_KEY, secretAccessKey: AWS_SECRET_KEY, }; const s3Client = new S3Client({ region: AWS_REG, credentials: credentials, });
객체 목록 : ListObjectsV2Command()
ListObjectsV2Command() 를 통해 S3에 저장된 폴더 내 객체 목록을 가져오는 요청 설정하고 S3클라이언트를 사용하여 폴더 내 객체 목록을 가져온다.
import { AWS_KEY, AWS_REG, AWS_SECRET_KEY } from "libs/config"; const { S3Client, ListObjectsV2Command } = require("@aws-sdk/client-s3"); export default function Project({ projects }: ProjectistObject) { //... const bucketName = "s3.personalblog"; const folderPrefixImages = "images/"; const [awsImages, setAwsImages] = useState<string[] | null>(null); const getObjectsInFolder = async () => { try { // 폴더 내 객체 목록을 가져오는 요청 설정 const commandInput = { Bucket: bucketName, Prefix: folderPrefixImages, }; const command = new ListObjectsV2Command(commandInput); // S3 클라이언트를 사용하여 폴더 내 객체 목록을 가져옴 const data = await s3Client.send(command); let objectlists = []; for (let object of data.Contents) { // 폴더 객체인 경우 리스트에 추가하지 않음 if (!object.Key.endsWith("/")) { objectlists.push(object.Key); } } return objectlists; } catch (error) { console.error(error); } }; return ( <></> ) }
getObjectsInFolder() 이 함수를 페이지 진입 시 실행 하도록 useEffect를 통해 setAwsImages에 저장한다.
useEffect(() => { const fetchObjects = async () => { try { const res = await getObjectsInFolder(); if (res) { const removeFolder = res.map((r: string) => r.split("/")[1]); setAwsImages(removeFolder); } } catch (error) { console.error("Error fetching objects:", error); } }; fetchObjects(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []);
해당 파일 명을 cloudfrontBaseUrl에 이어서 붙이면 S3에 저장된 이미지가 나온다.
{ awsImages?.map((imagePath: any) => ( <Image src={`${cloudfrontBaseUrl}/images/${imagePath}`} alt="image" width={300} height={300} priority placeholder="blur" blurDataURL={blurDataURL} key={imagePath} /> ))}
전체 코드
아래 코드에서는 aws 이미지들을 <Post /> 컴포넌트로 보내고 있다.
import { AWS_KEY, AWS_REG, AWS_SECRET_KEY } from "libs/config"; const { S3Client, ListObjectsV2Command } = require("@aws-sdk/client-s3"); export default function Project({ projects }: ProjectistObject) { //... //aws s3 image const credentials = { accessKeyId: AWS_KEY, secretAccessKey: AWS_SECRET_KEY, }; const s3Client = new S3Client({ region: AWS_REG, credentials: credentials, }); const bucketName = "s3.personalblog"; const folderPrefixImages = "images/"; const [awsImages, setAwsImages] = useState<string[] | null>(null); const getObjectsInFolder = async () => { try { // 폴더 내 객체 목록을 가져오는 요청 설정 const commandInput = { Bucket: bucketName, Prefix: folderPrefixImages, }; const command = new ListObjectsV2Command(commandInput); // S3 클라이언트를 사용하여 폴더 내 객체 목록을 가져옴 const data = await s3Client.send(command); let objectlists = []; for (let object of data.Contents) { // 폴더 객체인 경우 리스트에 추가하지 않음 if (!object.Key.endsWith("/")) { objectlists.push(object.Key); } } return objectlists; } catch (error) { console.error(error); } }; useEffect(() => { const fetchObjects = async () => { try { const res = await getObjectsInFolder(); if (res) { const removeFolder = res.map((r: string) => r.split("/")[1]); setAwsImages(removeFolder); } } catch (error) { console.error("Error fetching objects:", error); } }; fetchObjects(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return ( <> <Seo title={`MinSun's Blog | Projects`} url={BASE_URL + "/project"} desc={"진행했던 프로젝트들을 기록합니다."} /> {mounted && ( <div className="laptop-max-width"> <Title title={"Projects"} subMent={"진행했던 프로젝트들을 기록합니다."} /> <div className="post-content-area"> {/* .... */} <div className={cls( viewStyle === "gallery" ? "page-gallery-style grid-rows-3" : "page-list-style", "w-full min-h-[912px] lg:min-h-[904px]" )} > {useSortedData( filteredList.map((item: ListResults) => ( <Post key={item.id} item={item} viewStyle={viewStyle} tagCategory={tagCategory} awsImages={awsImages} /> )), sortedContent ).slice(indexOfFirst, indexOfLast)} </div> </div> {/* .... */} </div> )} </> ); } }
참고
https://inpa.tistory.com/entry/AWS-SDK-👨🏻💻-Nodejs-연동-및-SDK-기본-사용법
https://inpa.tistory.com/entry/AWS-SDK-👨🏻💻-Node-S3-메소드-예제-정리