일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 코틀린
- 개발자
- restful api
- react
- javascript
- front-end
- props
- java
- Nest.js
- file upload
- AWS
- state
- Producer
- back-end
- 자바
- Kotlin
- vue
- kafka
- 조건문
- Sequelize
- swagger
- 개발이 취미인 사람
- component
- spring boot
- class
- 반복문
- node.js
- It
- 상속
- SWIFT
- Today
- Total
개발이 취미인 사람
[Node.js] Koa Multer 파일 업로드 본문
- 지난 시간
안녕하세요. 지난 시간에는 Koa 웹 애플리케이션 프레임워크을 사용해서 RESTFaul API 서버를 만들어 보았습니다.
혹시 지난 글을 못 보신 분들은 아래 글을 통해 설치 및 구축을 하고 오시면 감사하겠습니다.
- 개요
이번 시간에는 RESTFul API에서 파일 업로드하는 부분에 대해서 알아보겠습니다.
Node.js에서 파일을 업로드하는 미들웨어는 다양합니다. 하지만 이 글에서는 @koa/multer라는 미들웨어를 사용해보겠습니다.
@koa/multer 미들웨어는 multer 미들웨어에 종속되어 사용됩니다. 그래서 같이 사용해야 됩니다.
- 설치
새로운 프로젝트를 만들어서 진행할 예정입니다. 아래 라이브러리(모듈)을 설치해주세요. :)
- npm init : 프로젝트 생성(package.json 파일 생성)
- npm install koa : Koa 웹 어플리케이션 프레임워크
- npm install @koa/router : Koa Route
- npm install @koa/cors : http 통신 허용
- npm install @koa/multer : multer 기반 모듈
- npm install multer : 파일 업로드 미들웨어
@koa/multer를 사용해야 하는 이유는 koa/multer 라이브러리가 deprecated(사용하지 않음) 되었습니다.
-
기본세팅
const Koa = require('koa');
const Router = require('@koa/router');
const cors = require('@koa/cors');
/**
* Multer 미들웨어는 파일 업로드를 위해 사용되는 multipart/form-data에서 사용된다.
* 다른 폼으로 데이터를 전송하면 적용이 안된다.
* Header의 명시해서 보내주는게 좋다.
*/
const multer = require('@koa/multer');
//파일을 저장할 디렉토리 설정 (현재 위치에 uploads라는 폴더가 생성되고 하위에 파일이 생성된다.)
const upload = multer({
dest: __dirname+'/uploads/', // 이미지 업로드 경로
})
app.use(cors())// Test를 하기 위해서 세팅 "실제 서버에 배포할 때는 아이피를 설정 해야된다."
app.listen(3000, () => console.log("Koa Multer Server Start"));
주석에도 설명을 남겨놨지만 Client에서 HTTP Header에 multipart/forom-data 라고 지정하지 않으면 안됩니다. (참고!)
3000번 포트 번호로 서버 시작
- 기능
- 단일 파일업로드
/**
* @author Ryan
* @description 단일 파일 업로드
*
* 클라이언트에서 file이라는 Key(fieldname) 값을 통해 파일을 전송하면 ctx.request.file 안에 파일 정보를 얻을 수 있다.
*
* 단일 이미지 전송이기 때문에 여러 파일을 보내게 되면 에러가 발생된다.
*
*/
router.post('/single/upload', upload.single('file'), (ctx, next) => {
const { fieldname, originalname, encoding, mimetype, destination, filename, path, size } = ctx.request.file
const { name } = ctx.request.body;
console.log("body 데이터 : ", name);
console.log("폼에 정의된 필드명 : ", fieldname);
console.log("사용자가 업로드한 파일 명 : ", originalname);
console.log("파일의 엔코딩 타입 : ", encoding);
console.log("파일의 Mime 타입 : ", mimetype);
console.log("파일이 저장된 폴더 : ", destination);
console.log("destinatin에 저장된 파일 명 : ", filename);
console.log("업로드된 파일의 전체 경로 ", path);
console.log("파일의 바이트(byte 사이즈)", size);
ctx.body = {ok: true, data: "Single Upload Ok"}
})
- 멀티 파일 업로드
/**
* @author Ryan
* @description 여러 파일 업로드
*
* 클라이언트에서 file이라는 Key(fieldname) 값을 통해 파일을 전송하면 ctx.request.files 안에 파일 정보를 배열([]) 형태로 얻을 수 있다.
*
* array('fieldname', maxCount) 필드 이름과 최대 파일 수를 정합니다.
* 지정된 수 보다 더 많은 파일을 업로드하면 에러가 발생합니다.
*/
router.post('/multipart/upload', upload.array('file'), (ctx, next) => {
const { name } = ctx.request.body;
console.log("body 데이터 : ", name);
//배열 형태이기 때문에 반복문을 통해 파일 정보를 알아낸다.
ctx.request.files.map(data => {
console.log("폼에 정의된 필드명 : ", data.fieldname);
console.log("사용자가 업로드한 파일 명 : ", data.originalname);
console.log("파일의 엔코딩 타입 : ", data.encoding);
console.log("파일의 Mime 타입 : ", data.mimetype);
console.log("파일이 저장된 폴더 : ", data.destination);
console.log("destinatin에 저장된 파일 명 : ", data.filename);
console.log("업로드된 파일의 전체 경로 ", data.path);
console.log("파일의 바이트(byte 사이즈)", data.size);
})
ctx.body = {ok: true, data: "Multipart Upload Ok"}
})
- 단일 & 멀티 파일 업로드
/**
* @author Ryan
* @description 단일 및 여러 파일 업로드
*
* fields를 설정해서 특정 파일은 단일 또는 여러 파일 그리고 특정 파일을 나눠서 업로드가 가능하다.
*
* Ex) 클라이언트가 요청할 때 pdf 파일은 한개를 받고 이미지 파일은 여러개를 받는 상황
* 이런식으로 정의해서 사용할 수 있다.
*/
const fileFields = upload.fields([
{ name: 'file1', maxCount: 1 },
{ name: 'file2', maxCount: 8 },
]);
router.post('/fields/upload', fileFields, (ctx, next) => {
const { file1, file2 } = ctx.request.files;
const { name } = ctx.request.body;
console.log("body 데이터 : ", name);
//배열 형태이기 때문에 반복문을 통해 파일 정보를 알아낸다.
file1.map(data => {
console.log("file1");
console.log(" ");
console.log("폼에 정의된 필드명 : ", data.fieldname);
console.log("사용자가 업로드한 파일 명 : ", data.originalname);
console.log("파일의 엔코딩 타입 : ", data.encoding);
console.log("파일의 Mime 타입 : ", data.mimetype);
console.log("파일이 저장된 폴더 : ", data.destination);
console.log("destinatin에 저장된 파일 명 : ", data.filename);
console.log("업로드된 파일의 전체 경로 ", data.path);
console.log("파일의 바이트(byte 사이즈)", data.size);
})
console.log(" ");
console.log("-----------------------------------------------");
console.log(" ");
//배열 형태이기 때문에 반복문을 통해 파일 정보를 알아낸다.
file2.map(data => {
console.log("file2");
console.log(" ");
console.log("폼에 정의된 필드명 : ", data.fieldname);
console.log("사용자가 업로드한 파일 명 : ", data.originalname);
console.log("파일의 엔코딩 타입 : ", data.encoding);
console.log("파일의 Mime 타입 : ", data.mimetype);
console.log("파일이 저장된 폴더 : ", data.destination);
console.log("destinatin에 저장된 파일 명 : ", data.filename);
console.log("업로드된 파일의 전체 경로 ", data.path);
console.log("파일의 바이트(byte 사이즈)", data.size);
})
ctx.body = {ok: true, data: "Fields Upload Ok"}
})
fields를 두 개 설정했기 때문에 구조분해를 통해 file1과 file2를 가져올 수 있습니다.
모든 업로드 되는 파일들은 현재 위치에 uploads라는 폴더 하위에 저장이 됩니다. (파일 이름은 임시 저장)
"파일 이름이 임시저장 하는 부분이 싫으시면 따로 설정 할 수 있습니다."
console.log
body 데이터 : Ryan
폼에 정의된 필드명 : file
사용자가 업로드한 파일 명 : Ryan.png
파일의 엔코딩 타입 : 7bit
파일의 Mime 타입 : image/png
파일이 저장된 폴더 : /Users/sinhangug/ryan/server/koa-multer/uploads/
destinatin에 저장된 파일 명 : 0d3908a8756cf6481a2742eb5597bcf2
업로드된 파일의 전체 경로 /Users/sinhangug/ryan/server/koa-multer/uploads/0d3908a8756cf6481a2742eb5597bcf2
파일의 바이트(byte 사이즈) 21111
로그에서 데이터를 확인 할 수 있습니다.
만약 임시 이름이 싫거나 특정 폴더를 지정하고 싶으면 아래 코드를 활용해서 옵션을 설정 할 수 있습니다.
// 파일 경로 및 이름 설정 옵션
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, '/tmp/my-uploads') // 파일 업로드 경로
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now()) //파일 이름 설정
}
})
const upload = multer({ storage: storage })
- destination 옵션은 어느 폴더안에 파일을 저장할 지 결정합니다. (이 옵션을 주지 않으면, 운영체제 시스템 임시 파일을 저장한느 기본 디렉토리를 사용합니다.)
- filename 옵션은 폴더안에 저장되는 파일 이름을 결정합니다. (디렉토리를 생성하지 않으면 에러가 발생!! )
Storage 옵션
multer에는 MemoryStorage 방식과 DiskStorage 방식 두 가지가 있습니다.
보통 AWS S3와 같은 외부 파일 스토리즈 서버에 이미지를 업로드를 할 때는 MemoryStorage를 사용합니다.
RAM 안에 이미지 Butter라는 값을 통해 값을 확인 할 수 있습니다.
하지만 해당 운영체제 RAM 용량이 적으면 데이터 손실 또는 에러가 발생할 수 있습니다.
그렇기 때문에 DiskStorage에 파일을 쓰고 삭제하는 방식을 추천드립니다.
DiskStorage 방식은 말 그대로 "Disk에 파일을 저장하겠다" 라고 생각하시면 됩니다. 그렇게 때문에 uploads라는 폴더 아래에 파일이 저장됩니다.
Limites & Filter 옵션
클라이언트가 아무 이미지나 올리면 안되겠죠? 이럴 때 사용할 수 있는 옵션입니다.
//multer 미들웨어 파일 제한 값 (Doc 공격으로부터 서버를 보호하는데 도움이 된다.)
const limits = {
fieldNameSize: 200, // 필드명 사이즈 최대값 (기본값 100bytes)
filedSize: 1024 * 1024, // 필드 사이즈 값 설정 (기본값 1MB)
fields: 2, // 파일 형식이 아닌 필드의 최대 개수 (기본 값 무제한)
fileSize : 16777216, //multipart 형식 폼에서 최대 파일 사이즈(bytes) "16MB 설정" (기본 값 무제한)
files : 10, //multipart 형식 폼에서 파일 필드 최대 개수 (기본 값 무제한)
}
/**
* @author Ryan
* @description 파일 업로드시 파일 체크 함수
*
* @param {Object} file 파일 정보
*
* {
* fieldname: 'file',
* originalname: '001.png',
* encoding: '7bit',
* mimetype: 'image/png'
* }
*
* @param {Function} callback 파일 업르도 허용 및 거부 처리
*
* 허용: callback(null, true);
* 거부: callback(null, false);
*/
const fileFilter = (req, file, callback) =>{
const typeArray = file.mimetype.split('/');
const fileType = typeArray[1]; // 이미지 확장자 추출
//이미지 확장자 구분 검사
if(fileType == 'jpg' || fileType == 'jpeg' || fileType == 'png'){
callback(null, true)
}else {
// return callback(new Error("*.jpg, *.jpeg, *.png 파일만 업로드가 가능합니다."), false)
return callback({message: "*.jpg, *.jpeg, *.png 파일만 업로드가 가능합니다."}, false)
}
}
//파일을 저장할 디렉토리 설정 (현재 위치에 uploads라는 폴더가 생성되고 하위에 파일이 생성된다.)
const upload = multer({
dest: __dirname+'/uploads/', // 이미지 업로드 경로
limits: limits, // 이미지 업로드 제한 설정
fileFilter : fileFilter // 이미지 업로드 필터링 설정
})
기존 multer 코드 안에 limits와 fileFilter 항목에 옵션을 설정할 수 있습니다.
만약 에러가 발생한다면 multer 미들웨어는 Koa 프레임워크에 위임 합니다.
Koa에 Error Handler를 설정해서 에러를 캐치하면 됩니다.
/**
* @author Ryan
* @description Error Handler
*
* Express와 달리 Koa에서는 Error Handler를 라우터 보다 위에 선언해야됩니다.
*/
app.use(async(ctx, next) => {
try {
await next();
} catch (err) {
// will only respond with JSON
ctx.status = err.statusCode || err.status || 500;
ctx.body = { ok: false, data: err.message };
}
})
위 코드는 가장 아래에 설정해야 됩니다.
app.use는 모든 요청에 대해서 캐치가 가능하기 때문에 우리는 에러가 발생했을 때만 해당 라우터가 실행하기 때문입니다.
소스 저장소
GitHub : github.com/Ryan-Sin/Node_Koa_Multer
- 참고 사이트
GitHub : github.com/expressjs/multer/blob/master/doc/README-ko.md
GitHub : github.com/koajs/multer
'백앤드(Back-End) > Node.JS' 카테고리의 다른 글
[Node.js] Sequelize 개념 및 설치 (4) | 2021.02.10 |
---|---|
[Node.js] 디렉토리 & 파일 쓰기, 읽기, 삭제, 존재 여부 (2) | 2021.01.19 |
[Node.js] Express Multer 파일 업로드 (0) | 2021.01.17 |
[Node.js] Koa RESTFul API 서버 만들기 (0) | 2021.01.16 |
[Node.js] Koa 서버 구축 (0) | 2021.01.16 |