📌 개념 정리
- 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을 통한 빠르고 안전한 이미지 전송
🚦 동작 원리 및 구조
- 사용자가 웹페이지에서 이미지를 업로드
- Node.js 서버(Express)가 이미지를 받아 EC2 인스턴스에 저장
- 저장된 이미지를 AWS SDK를 통해 S3 버킷으로 업로드
- 업로드된 이미지를 S3에서 목록으로 조회해 웹페이지에 표시
- 이미지 접근을 위해 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 |