이번 시간에는 지난 시간에 구축한 AWS S3 서버를 이용해서 node.js & express app으로 파일 업로드, 삭제, 다운로드 등을 어떻게 하는지 살펴보겠습니다. 아직 S3를 구축하지 못했다면 지난 글을 참고해서 S3를 구축합니다.
S3를 이용한 이미지 서버 만들기 - I
AWS S3(Amazon Simple Storage Service)는 Amazon Web Services(AWS)에서 제공하는 객체 스토리지 서비스입니다. 이번 시간에는 S3를 이용해서 이미지 서버를 만드는 방법에 대해서 살펴보겠습니다. 1. S3 검색 및
hoazzinews.tistory.com
1. node.js express 프로젝트 만들기
> npm init
2. 필요한 모듈 설치
필요한 모듈을 순차적으로 설치 합니다.
> npm install express
express는 Node.js에서 가장 많이 사용되는 웹 프레임워크입니다. HTTP 서버 및 RESTful API를 구현하기 위해 설치합니다.
> npm install ejs
ejs는 Embedded JavaScript Templating의 약자로, HTML 파일 내에 JavaScript 코드를 삽입하여 동적으로 콘텐츠를 렌더링할 수 있게 해주는 뷰 템플릿 엔진입니다.
> npm install compression
compression은 HTTP 응답 데이터를 압축하는 미들웨어입니다. HTTP 응답을 Gzip이나 Brotli 등의 방식으로 압축하여 클라이언트로 보내면, 네트워크 대역폭을 절약하고 페이지 로딩 속도를 향상시킬 수 있습니다.
> npm install uuid4
UUID v4는 랜덤으로 고유한 값을 생성합니다. 파일명, 사용자 ID 등에서 고유한 식별자를 생성할 때 유용합니다.
> npm install multer
multer는 파일 업로드를 처리하기 위한 미들웨어입니다.
> npm install multer-s3
multer-s3는 multer의 확장 모듈로, 파일을 AWS S3 버킷에 직접 업로드할 수 있게 해주는 라이브러리입니다. multer-s3를 사용하면 로컬 서버가 아닌 AWS S3에 파일을 저장할 수 있습니다.
> npm install @aws-sdk/client-s3
@aws-sdk/client-s3는 AWS SDK for JavaScript (v3)의 S3 클라이언트 라이브러리입니다. 이 라이브러리는 AWS S3 서비스와 상호작용할 수 있게 해주며, 파일 업로드, 다운로드, 삭제 등 다양한 작업을 수행할 수 있습니다.
package.json에서 설치된 모듈을 확인할 수 있습니다.
{
"name": "s3ex",
"version": "1.0.0",
"description": "",
"license": "ISC",
"author": "",
"type": "commonjs",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"@aws-sdk/client-s3": "^3.717.0",
"compression": "^1.7.5",
"ejs": "^3.1.10",
"express": "^4.21.2",
"multer": "^1.4.5-lts.1",
"multer-s3": "^3.0.1",
"uuid4": "^2.0.3"
}
}
3. 애플리이션 실행 파일 생성
main.js를 만들고 다음과 같이 코딩합니다.
const express = require('express');
const multer = require('multer');
const app = express();
const compression = require('compression');
// view tmeplate setting START
app.set('view engine', 'ejs');
app.set('views', './view');
// view tmeplate setting END
app.get('/', (req, res) => {
console.log('/');
res.redirect('/home');
});
// router setting START
const homeRouter = require('./route/homeRouter');
app.use('/home', homeRouter);
const fileRouter = require('./route/fileRouter');
app.use('/file', fileRouter);
// router setting END
app.listen(3000);
4. router 생성
route 폴더를 만든 후 homeRouter.js, fileRouter.js를 만들고 다음과 같이 코딩합니다.
homeRouter.js 파일
const express = require('express');
const router = express.Router();
// /home
router.get('/', (req, res) => {
console.log('/home');
res.render('home');
});
module.exports = router;
fileRouter.js 파일
const express = require('express');
const router = express.Router();
const { S3Client, PutObjectCommand, GetObjectCommand, DeleteObjectCommand } = require('@aws-sdk/client-s3');
const path = require('path');
const multer = require('multer');
const multerS3 = require('multer-s3');
const uuid4 = require('uuid4');
// AWS S3 설정 (AWS SDK v3)
const s3Client = new S3Client({
region: 'ap-northeast-2',
credentials: {
accessKeyId: 'S3 ACCESS KEY',
secretAccessKey: 'S3 SECRET ACCESS KEY',
},
});
// Multer 설정: S3와 통합
const upload = multer({
storage: multerS3({
s3: s3Client, // v3에서 S3 클라이언트 객체 전달
bucket: 'S3 BUCKET 이름', // S3 버킷 이름
acl: 'public-read', // 파일을 공개적으로 읽을 수 있도록 설정
metadata: function (req, file, cb) {
cb(null, { fieldName: file.fieldname });
},
key: function (req, file, cb) {
cb(null, uuid4().replaceAll('-', '') + Date.now().toString() + path.extname(file.originalname)); // 파일 이름을 고유하게 설정
}
})
});
// /file/upload
router.post('/upload', upload.single('profile'), (req, res) => {
console.log('/file/upload');
if (!req.file)
return res.status(400).send('FILE UPLOAD FAIL!');
// S3에서 업로드한 파일의 URL을 응답으로 반환
const fileUrl = req.file.location;
const fileName = req.file.key;
res.render('home', {
message: 'FILE UPLOAD SUCCESS!',
fileUrl: fileUrl,
fileName: fileName
});
});
// /file/download
router.get('/download', async (req, res) => {
console.log('/file/download');
const fileName = req.query.file_name;
try {
const getObjectCommand = new GetObjectCommand({
Bucket: 'S3 BUCKET 이름', // S3 버킷 이름
Key: fileName, // 다운로드할 파일의 Key
});
const data = await s3Client.send(getObjectCommand);
// 파일의 MIME 타입이 정상적으로 전달되도록 설정
const contentType = data.ContentType || 'application/octet-stream'; // 기본값은 binary stream
// 파일을 다운로드 스트림으로 전달
res.setHeader('Content-Disposition', `attachment; filename="${fileName}"`);
res.setHeader('Content-Type', contentType);
// S3에서 가져온 파일을 바로 응답으로 전달
data.Body.pipe(res); // data.Body는 ReadableStream입니다.
} catch (err) {
console.error(err);
res.status(500).send('FILE DOWNLOAD ERROR!');
}
});
// /file/delete
router.get('/delete', async (req, res) => {
console.log('/file/delete');
const fileName = req.query.file_name;
try {
const deleteObjectCommand = new DeleteObjectCommand({
Bucket: 'S3 BUCKET 이름', // S3 버킷 이름
Key: fileName, // 삭제할 파일의 Key
});
await s3Client.send(deleteObjectCommand);
res.render('home', {
message: 'FILE DELETE SUCCESS!',
});
} catch (err) {
console.error(err);
res.render('home', {
message: 'FILE DELETE FAIL!',
});
}
});
module.exports = router;
5. view 생성
view 폴더를 만든 후 home.ejs를 만들고 다음과 같이 코딩합니다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>s3ex</title>
<style>
.uploaded_img {
max-width: 300px;
min-width: 300px;
}
</style>
<script>
// 삭제 요청을 서버로 보냄
function deleteFile(fileName) {
console.log('deleteFile()', fileName);
location.href = '/file/delete?file_name=' + fileName;
}
// 다운로드 요청을 서버로 보냄
function downloadFile(fileName) {
console.log('downloadFile()', fileName);
location.href = '/file/download?file_name=' + fileName;
}
</script>
</head>
<body>
<!-- 파일 업로드 -->
<form action="/file/upload"
method="post"
enctype="multipart/form-data">
<input type="file" name="profile">
<input type="submit" value="FILE UPLOAD">
</form>
<!-- fileUrl이 존재할 때만 이미지와 파일 이름을 표시 -->
<% if (typeof fileUrl !== 'undefined' && fileUrl !== null) { %>
<div>
<img class="uploaded_img" src="<%= fileUrl %>" alt="Uploaded File"/><br>
Message: <span><%= message %></span><br>
File URL: <span><%= fileUrl %></span><br>
File Name: <span><%= fileName %></span><br>
<!-- 파일 삭제 및 다운로드 버튼 -->
<button onclick="deleteFile('<%= fileName %>')">FILE DELETE</button>
<br>
<button onclick="downloadFile('<%= fileName %>')">FILE DOWNLOAD</button>
</div>
<% } else { %>
<% if (typeof message !== 'undefined') { %>
Message: <span><%= message %></span><br>
<% } else { %>
Message: <span>NO FILE UPLOADED YET</span><br>
<% } %>
<% } %>
</body>
</html>
6. 애플리케이션 실행
애플리케이션을 실행하고 파일 업로드, 다운로드, 삭제 기능을 확인합니다.
> node main.js
이번 시간에는 node.js & express에서 s3 버킷을 이용하는 방법에 대해서 살펴봤습니다.
전체 소스 첨부합니다.
'aws' 카테고리의 다른 글
AWS S3에 파일 업로드, 다운로드, 삭제하기(feat. spring boot) (1) | 2024.12.18 |
---|---|
S3를 이용한 이미지 서버 만들기 (3) | 2024.12.17 |
AWS RDS MySQL을 사용할 때 외부 IP 접근을 설정하는 방법과 차이점 (0) | 2024.12.01 |
AWS RDS 서버 만들기 (0) | 2024.11.25 |
putty를 이용해서 AWS EC2에 접속하기 (0) | 2024.11.25 |