이번 포스팅에서는 파일업로드에 사용되는 라이브러리인 multer에 대해 알아보고자 한다. multer를 사용해서 이미지 파일들을 업로드 해보도록 하자.
< 목차 >
- multer 세팅하기
- single 파일 업로드
- multiple 파일 업로드
1. multer 세팅하기
multer는 파일업로드를 도와주는 외부 라이브러리이므로 터미널 창을 열고 multer를 설치해주도록 하자.
npm install multer --save
html을 이용해 파일업로드 창을 만들기 위해서는 다음과 같이 <form>엘리먼트를 작성해주면 된다.
<form method="post" action="/upload" enctype="multipart/form-data">
<input type="text" name="subject">
<input type="file" name="upload">
<input type="submit" value="전송">
</form>
input 박스의 type을 "file"로 설정하고 <form> 엘리먼트의 속성으로 enctype을 지정해주도록 하자. 이때 enctype을 "multipart/form-data"로 지정해줘야 한다. (참고로 <form>엘리먼트의 enctype 디폴트 값은 application/x-www-form-urlencoded 이다.)
우리가 업로드하고자 하는 이미지 파일들 역시 컴퓨터에게는 결국 텍스트 파일일 뿐이다. 위에 작성한 <form>엘리먼트의 내용을 토대로 직접 파일을 전송해보면서 해당 내용을 확인해보자.
파일을 업로드해서 서버로 post 요청을 보내면 위와 같이 Request Body의 payload 부분에 외계어같은 텍스트들이 들어가는 것을 볼 수 있다. 해당 텍스트들이 바로 우리가 전송한 이미지 파일인 것이다. Request Body의 payload로 실려오는 이러한 텍스트들을 해석하기 위해서는 서버 쪽에서 적절한 조치를 취해줘야만 한다.
HTTP 패킷의 Request Body 영역의 데이터를 읽는 미들웨어들에 대해 살펴본 적이 있다. 대표적인 예로 application/x-www-form-urlencoded 형태를 읽기 위해서 우리는 app.use(express.urlencoded({extended: true})) 를 사용하였다. 그리고 JSON 포맷의 데이터를 읽기 위해서는 app.use(express.json()) 을 사용하였다. (해당 내용은 아래글 참고)
2022.02.15 - [Node.js/express] - Node.js - express (11) express.json()
마찬가지로 multipart/form-data 형식의 데이터를 읽을 수 있게 해주는 미들웨어가 필요한데 multer 라이브러리를 사용해서 이러한 미들웨어를 만들 수 있다. 우선 multer( ) 함수를 사용해서 다음과 같이 객체를 만들어주도록 하자.
const multer = require('multer')
const path = require('path')
const upload = multer({
storage: multer.diskStorage({
destination: (req, file, done)=>{
done(null, 'uploads/')
// 첫번째 인자값은 에러처리에 대한 부분
// 두번째 인자값은 파일이 저장 될 디렉토리
},
filename: (req, file, done)=>{
// file.originalname : 사용자가 업로드한 파일명
const ext = path.extname(file.originalname)
const filename = path.basename(file.originalname, ext) + '_' + Date.now() + ext
done(null, filename)
// 첫번째 인자값은 에러처리에 대한 부분
// 두번째 인자값은 서버 컴퓨터에 실제로 저장할 파일명
}
}),
limits: { fileSize: 5*1024*1024 } // 5MB
// 최대 파일사이즈 설정
})
multer( ) 함수 안에 객체 형태로 인자값을 전달하게 되는데 storage 속성값을 통해 업로드 된 파일을 어디에 저장할지 지정할 수 있다. multer.diskStorage( )를 작성함으로써 서버 컴퓨터의 하드디스크에 업로드 된 파일들을 저장하게 된다. multer.diskStorage( )는 인자값으로 객체를 받을 수 있는데 해당 객체의 destination 속성값을 이용하면 파일이 저장될 디렉토리를 설정할 수 있고 filename 속성값을 통해서는 저장될 때의 파일명을 설정할 수 있다.
destination 함수의 인자값으로 done이라는 콜백함수가 들어가는데 done 함수의 두번째 인자값을 'uploads/' 로 하게 되면 uploads 디렉토리 안에 업로드 된 파일들이 저장되게 된다. filename 함수의 인자값으로 들어가는 done 콜백함수 역시 두번째 인자값으로 서버 컴퓨터에 저장될 파일명이 들어가게 된다.
참고로 filename 속성값에서 사용한 file.originalname은 클라이언트(사용자)가 업로드한 파일명을 나타낸다. Node.js 내부 라이브러리인 path 라이브러리를 사용해서 서버 컴퓨터에 저장될 파일명을 만들어주었다. (path 라이브러리 사용법은 아래글 참고)
2022.03.15 - [Node.js/node js] - Node.js - path 라이브러리
이제 multer 라이브러리가 제공하는 미들웨어를 사용하기 위한 기본 세팅이 끝났다. 어떠한 형태의 파일 업로드를 구현할 것인지에 따라 upload 객체를 사용해서 적절한 메소드와 함께 작성해주면 된다. 여기서 한가지 짚고 넘어갈 것은 이미지 업로드 미들웨어는 app.use( ) 안에 작성하는 것이 아니라 파일 업로드가 구현되는 라우터 안에만 작성해주면 된다는 것이다.
2. single 파일 업로드
위에서 생성한 upload 객체 안에 있는 single( ) 함수를 사용해서 single 파일 업로드 미들웨어를 만들 수 있다. 해당 미들웨어는 다음과 같다.
upload.single('upload')
upload.single( ) 함수의 인자값으로는 html 파일에서 작성한 파일 업로드 input 박스의 name값을 넣어주면 된다. html 파일을 살펴보면 <form>엘리먼트의 속성값이 method="post" , action="/upload"인 것을 알 수 있다. 따라서 다음과 같은 라우터를 만들어서 실행해주면 된다.
app.post('/upload', upload.single('upload'), (req, res)=>{
// upload.single() 미들웨어가 req.file을 만들어준다.
// req.file에 파일에 대한 데이터가 담긴다.
console.log(req.file)
console.log(req.body)
res.send('uploaded')
})
console.log( ) 를 이용해서 req.file을 출력해본 이유는 upload.single( ) 미들웨어에 의해 req 객체 안에 file이라는 객체가 생성되었기 때문이다. upload.single( )에 의해 req.file 객체가 생기고 해당 객체 안에 업로드 된 파일의 정보가 담기게 된다. 뿐만 아니라 upload.single( ) 미들웨어는 파일에 관한 정보를 제외한 나머지 데이터를 req.body에 담아준다.
// server.js
const express = require('express')
const nunjucks = require('nunjucks')
const app = express()
const multer = require('multer')
const path = require('path')
const upload = multer({
storage: multer.diskStorage({
destination: (req, file, done)=>{
done(null, 'uploads/')
// 첫번째 인자값은 에러처리에 대한 부분
// 두번째 인자값은 파일이 저장 될 디렉토리
},
filename: (req, file, done)=>{
const ext = path.extname(file.originalname)
const filename = path.basename(file.originalname, ext) + '_' + Date.now() + ext
done(null, filename)
// 첫번째 인자값은 에러처리에 대한 부분
// 두번째 인자값은 실제로 저장할 파일명
}
}),
limits: { fileSize: 5*1024*1024 }
})
app.set('view engine', 'html')
nunjucks.configure('./views', {
express: app,
watch: true
})
app.get('/single', (req, res)=>{
res.render('single.html')
})
app.post('/upload', upload.single('upload'), (req, res)=>{
// upload.single() 미들웨어가 req.file을 만들어준다.
// req.file에 파일에 대한 데이터가 담긴다.
console.log(req.file)
console.log(req.body)
res.send('uploaded')
})
app.listen(3000, ()=>{
console.log('server onload')
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>Hello multer!!</h1>
<!--
Content-type : application/json
Content-type : x-www-form-urlencoded
파일 업로드를 할 때,
Request Body 영역의 content-type을 지정해줘야 한다.
form 엘리먼트의 enctype 디폴트값은 application/x-www-form-urlencoded
-->
<form method="post" action="/upload" enctype="multipart/form-data">
<input type="text" name="subject">
<input type="file" name="upload">
<input type="submit" value="전송">
</form>
</body>
</html>
위의 코드는 메인 서버 파일인 server.js 파일과 single.html 파일이다. 서버를 실행시키고 실제 파일 업로드를 진행해보면 다음과 같이 uploads 디렉토리 안에 이미지 파일이 저장되는 것을 확인할 수 있다.
3. multiple 파일 업로드
앞서 살펴본 single 파일 업로드는 파일 업로드를 할 때 한개의 파일만을 업로드할 수 있는 방법이었다. 이번에 살펴볼 것은 한번에 여러개의 이미지 파일을 업로드 하는 법에 대한 것이다. multer 라이브러리를 사용해서 upload 객체를 생성하는 일련의 과정이 single 파일 업로드와 동일하다. 차이점이 있다면 html 페이지에서 파일업로드 input 박스에 multiple 속성값을 추가해야 한다는 것과 upload 객체를 사용해서 미들웨어를 만들 때 upload.single( )이 아닌 upload.array( ) 를 사용한다는 것이다.
<form method="post" action="/upload2" enctype="multipart/form-data">
<input type="text" name="subject">
<!-- multiple 속성값이 있으면 여러개의 파일을 업로드 할 수 있다.-->
<input type="file" name="upload" multiple>
<input type="submit" value="전송">
</form>
html 파일을 위와 같이 수정하고 server.js 파일에서는 "/upload2" 라우터를 다음과 같이 만들어주면 된다.
app.post('/upload2', upload.array('upload'), (req, res)=>{
// multiple 파일업로드는 미들웨어가 upload.array()
// req.files에 파일에 대한 데이터가 담긴다.
console.log(req.files)
console.log(req.body)
res.send('uploaded')
})
multiple 파일 업로드에서는 upload.array( ) 미들웨어를 사용하며 인자값으로 전달하는 'upload'는 upload.single( )과 마찬가지로 html 파일에서 작성한 파일 업로드 input 박스의 name값이다. 그리고 req.file에 s가 붙은 req.files에 파일에 대한 정보가 담기게 된다. req.body에는 마찬가지로 파일 정보를 제외한 나머지 데이터가 들어간다.
P.S.
파일 업로드 input 박스가 여러개일 경우에 처리하는 방법과 비동기 파일 업로드 내용도 다루려고 했지만,, 글이 무척 길어지는 것 같아 해당 내용은 다음 포스팅에서 다뤄보도록 하겠다.
'Node > Express' 카테고리의 다른 글
Node.js - express (19) WebSocket (0) | 2022.03.18 |
---|---|
Node.js - express (18) multer (2) (0) | 2022.03.15 |
Node.js - express (16) CORS (0) | 2022.03.13 |
Node.js - express (15) Ajax - fetch , axios (0) | 2022.03.07 |
Node.js - express (14) Ajax - XMLHttpRequest( ) (0) | 2022.03.06 |