16강 미니 프로젝트(사진 공유 웹사이트)_3 (AWS)

2025. 4. 11. 16:49·프로젝트

📌 개념 정리

  • Express Generator 구조 이해
    • views 폴더: 프론트엔드 영역, EJS(템플릿 엔진), HTML 등을 관리
    • routes 폴더: 백엔드 API 코드 관리
  • AWS SDK for JavaScript
    • AWS 서비스를 Node.js에서 사용할 수 있도록 하는 SDK
    • EC2 인스턴스에서 S3로 파일 업로드 가능
  • IAM 역할(Role)
    • AWS 서비스에 접근 권한을 부여할 때 사용
    • EC2 인스턴스에 S3 접근 권한 부여 시 사용
  • CloudFront와 OAC(Origin Access Control)
    • S3 버킷의 객체를 퍼블릭하게 접근할 수 있게 하는 기능
    • CDN을 통한 빠르고 안전한 이미지 전송

🚦 동작 원리 및 구조

  1. 사용자가 웹페이지에서 이미지를 업로드
  2. Node.js 서버(Express)가 이미지를 받아 EC2 인스턴스에 저장
  3. 저장된 이미지를 AWS SDK를 통해 S3 버킷으로 업로드
  4. 업로드된 이미지를 S3에서 목록으로 조회해 웹페이지에 표시
  5. 이미지 접근을 위해 CloudFront CDN을 활용 (OAC)

💻 코드 예시 및 흐름 분석

🔸 AWS SDK 설치 프로젝트 최상위 폴더에서 설치 cd project

npm install @aws-sdk/client-s3

🔸 images.js 수정 (라우트) 8번 밑 클라이언트 삽입 및 route get 삽입 ( bucket주소 변경) 

38번 버켓주소도변경

 

  1 var express = require('express');
  2 var router = express.Router();
  3 var fs = require('fs');
  4 var path = require('path');
  5 var multer = require('multer');
  6 var upload = multer({ dest: path.join(__dirname, '..', 'uploads') });
 
  8 var {
  9     S3Client,
 10     PutObjectCommand,
 11     ListObjectsV2Command,
 12 } = require('@aws-sdk/client-s3');
 13 const s3Client = new S3Client({ region: 'ap-northeast-2' });
 14
 15 router.get('/', function (req, res, next) {
 16     s3Client
 17         .send(
 18             new ListObjectsV2Command({
 19                 Bucket: 'rainsos-bucket-20250411',
 20                 MaxKeys: 50,
 21             })
 22         )
 23         .then((data) => {
 24             res.send(data.Contents);
 25         })
 26         .catch((error) => {
 27             console.log(error);
 28         });
 29 });
 30
 31 router.post('/', upload.single('new-image'), function (req, res, next) {
 32     console.dir(req.file);
 33
 34     fs.readFile(req.file.path, function (err, data) {
 35         s3Client
 36             .send(
 37                 new PutObjectCommand({
 38                     Bucket: 'rainsos-bucket-20250411',
 39                     Key: req.file.filename,
 40                     Body: data,
 41                     ContentType: req.file.mimetype,
 42                 })
 43             )
 44             .then((data) => {
 45                 console.log(data);
 46                 res.send(data);
 47             })
 48             .catch((error) => {
 49                 console.log(error);
 50             });
 51     });
 52 });
 53 module.exports = router;

 

- IAM 역할(Role) 등록 EC2 에서 보안눌려서 등록

- S3에서 버킷을 동일한 이름으로 만든다. 치

- Cloudfront 에서 배포 생성해서 S3블럭에 연동 배포 도메인주소필요 

 

밑에코드는 예시

const { S3Client, PutObjectCommand, ListObjectsV2Command } = require('@aws-sdk/client-s3');
const s3 = new S3Client({ region: 'ap-northeast-2' });

// 이미지 업로드
router.post('/', upload.single('image'), async (req, res) => {
  const params = {
    Bucket: '자신의-버킷-이름',
    Key: req.file.originalname,
    Body: fs.createReadStream(req.file.path),
    ContentType: req.file.mimetype,
  };

  try {
    const data = await s3.send(new PutObjectCommand(params));
    res.status(200).send(data);
  } catch (err) {
    console.error(err);
    res.status(500).send(err);
  }
});

// 이미지 목록 조회
router.get('/', async (req, res) => {
  const params = {
    Bucket: '자신의-버킷-이름',
    MaxKeys: 50,
  };

  try {
    const data = await s3.send(new ListObjectsV2Command(params));
    res.status(200).send(data.Contents);
  } catch (err) {
    console.error(err);
    res.status(500).send(err);
  }
});

 

 

 

🔸 index.ejs (뷰) 최종 수정 19번라인 추가 /  31번부터 추가 그뒤에 52번에 배포 도메인수정

 <!DOCTYPE html>
  2 <html>
  3   <head>
  4     <title><%= title %></title>
  5     <link rel='stylesheet' href='/stylesheets/style.css' />
  6     <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.5/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-SgOJa3DmI69IUzQ2PVdRZhwQ+dy64/BUtbMJw1MZ8t5HZApcHrRKUc4W0kG87    9m7" crossorigin="anonymous">
  7   </head>
  8   <body>
  9     <h1><%= title %></h1>
 10     <p>Welcome to <%= title %></p>
 11
 12     <div class="input-group mb-3">
 13     <label class="input-group-text" for="file-upload">Upload</label>
 14     <input type="file" class="form-control" id="file-upload" name="new-image" >
 15     </div>
 16     <div id="progres" class="progress" role="progressbar" aria-label="Animated striped example" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">
 17         <div class="progress-bar progress-bar-striped progress-bar-animated" style="width: 0%"></div>
 18     </div>
 19     <div id="image-list"></div>
 20
 21     <script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
 22     <script src="https://code.jquery.com/ui/1.14.1/jquery-ui.min.js" integrity="sha256-AlTido85uXPlSyyaZNsjJXeCs07eSv3r43kyCVc8ChI=" crossorigin="anonymous"></script>
 23
 24     <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.5/dist/js/bootstrap.bundle.min.js" integrity="sha384-k6d4wzSIapyDyv1kpU366/PK5hCdSbCRGRCMv+eplOQJWyd1fbcAu9OCUj5zNLiq" crosso    rigin="anonymous"></script>
 25     <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js" integrity="sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r" crossorig    in="anonymous"></script>
 26     <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.5/dist/js/bootstrap.min.js" integrity="sha384-VQqxDN0EQCkWoxt/0vsQvZswzTHUVOImccYmSyhJTp7kGtPed0Qcx8rK9h9YEgx+" crossorigin="    anonymous"></script>
 27     <script
 28             src="https://blueimp.github.io/jQuery-File-Upload/js/jquery.fileupload.js"
 29             crossorigin="anonymous"></script>
 30     <script>
 31            $(function () {
 32                 $('#file-upload').fileupload({
 33                     url: '/images',
 34                     dataType: 'json',
 35                     progressall: function (e, data) {
 36                         var progress = parseInt(
 37                             (data.loaded / data.total) * 100,
 38                             10
 39                         );
 40                         $('#progress .progress-bar').css(
 41                             'width',
 42                             progress + '%'
 43                         );
 44                     },
 45                 });
 46             });
 47             $.getJSON('/images', function (data) {
 48                 $.each(data, function (i, e) {
 49                     var img = $('<img>');
 50                     img.attr(
 51                         'src',
 52                         'https://d35jky9c8nnx1r.cloudfront.net/' + e.Key
 53                     )
 54                         .attr({ width: '200px', height: '200px' })
 55                         .addClass('img-thumbnail');
 56
 57                     $('#image-list').append(img);
 58                 });
 59             });
 60     </script>
 61
 62   </body>
 63 </html>

🧪 실전 사례

  • 웹사이트에서 프로필 사진이나 게시판 이미지 업로드할 때
  • 사용자 업로드 이미지를 효율적으로 관리 및 CDN을 통해 빠르게 제공할 때

🧠 고급 팁 or 자주 하는 실수

  • 📍 IAM 역할 설정: EC2 인스턴스가 S3에 접근할 권한을 반드시 IAM 역할을 통해 부여해야 함.
  • 📍 리전 주의: S3 버킷과 EC2 인스턴스의 리전을 동일하게 설정해야 문제 방지.
  • 📍 CloudFront 설정: 반드시 OAC를 설정하고 S3 버킷 정책 업데이트를 잊지 말 것.

✅ 마무리 요약 및 복습 포인트

  • views는 프론트, routes는 백엔드 담당
  • 파일 업로드는 multer 라이브러리 사용
  • S3 업로드는 AWS SDK로 구현
  • IAM 역할을 통해 EC2에 S3 접근 권한 부여
  • CloudFront로 이미지에 안전하게 접근 가능하게 설정

📌 실습하면서 발생하는 오류 메시지를 정확히 읽고 원인 파악 습관화!

'프로젝트' 카테고리의 다른 글

Chapter 1 네이버 정적 스크랩핑,크롤러 프로젝트  (0) 2025.04.14
16강 미니 프로젝트(사진 공유 웹사이트)_4 (AWS)  (0) 2025.04.11
16강 미니 프로젝트(사진 공유 웹사이트)_2 (AWS)  (0) 2025.04.11
16강 미니 프로젝트(사진 공유 웹사이트)_1 (AWS)  (0) 2025.04.11
Project. Admin 페이지 프론트단 제작 프로젝트 (250402)  (0) 2025.04.02
'프로젝트' 카테고리의 다른 글
  • Chapter 1 네이버 정적 스크랩핑,크롤러 프로젝트
  • 16강 미니 프로젝트(사진 공유 웹사이트)_4 (AWS)
  • 16강 미니 프로젝트(사진 공유 웹사이트)_2 (AWS)
  • 16강 미니 프로젝트(사진 공유 웹사이트)_1 (AWS)
Chansman
Chansman
안녕하세요! 코딩을 시작한 지 얼마 되지 않은 초보 개발자 찬스맨입니다. 이 블로그는 제 학습 기록을 남기고, 다양한 코딩 실습을 통해 성장하는 과정을 공유하려고 합니다. 초보자의 눈높이에 맞춘 실습과 팁, 그리고 개발하면서 겪은 어려움과 해결 과정을 솔직하게 풀어내려 합니다. 함께 성장하는 개발자 커뮤니티가 되기를 바랍니다.
  • Chansman
    찬스맨의 프로그래밍 스토리
    Chansman
  • 전체
    오늘
    어제
    • 분류 전체보기 (702)
      • Python (32)
      • 프로젝트 (43)
      • 과제 (25)
      • Database (40)
      • 멘토링 (11)
      • 특강 (37)
      • 기술블로그 (40)
      • 기술블로그-Fastapi편 (33)
      • 기술블로그-Django편 (153)
      • 기술블로그-Flask편 (36)
      • AI 분석 (4)
      • HTML & CSS (31)
      • JavaScript (17)
      • AWS_Cloud (21)
      • 웹스크래핑과 데이터 수집 (14)
      • Flask (42)
      • Django (77)
      • Fastapi (16)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
Chansman
16강 미니 프로젝트(사진 공유 웹사이트)_3 (AWS)

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.