이번 포스팅에서는 파일업로드 창이 여러개일 때 multer를 사용해서 해당 이슈를 해결하는 방법과 비동기 파일 업로드에 대해 다뤄보려고 한다. 이전에 작성한 multer(1)과 이어지는 글이므로 기본적인 세팅법과 메인 서버 파일인 server.js 파일의 내용은 아래 글을 참고하도록 하자.
2022.03.15 - [Node.js/express] - Node.js - express (17) multer (1)
< 목차 >
- 파일 업로드 창이 여러개일 때
- 비동기 파일 업로드
1. 파일 업로드 창이 여러개일 때
우선 저번 포스팅에서 사용한 single.html 파일과 server.js 파일은 아래와 같다.
<!-- single.html -->
<!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>
<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
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')
})
single.html 에 있는 파일 업로드 input 박스는 한번에 하나의 파일만을 업로드 할 수 있는 형태이다. 다음과 같이 여러개의 input 박스를 만들어서 하나의 <form>엘리먼트 안에 여러개의 파일 업로드 창이 존재할 경우 server.js 파일에서는 어떠한 미들웨어를 사용해야 하는지 알아보도록 하자.
<form method="post" action="/upload3" enctype="multipart/form-data">
<input type="text" name="subject">
<input type="file" name="upload1">
<input type="file" name="upload2">
<input type="file" name="upload3">
<input type="file" name="upload4">
<input type="submit" value="전송">
</form>
서로 다른 name값을 갖고 있는 여러개의 input 박스들이 method="post" action="/upload3" 속성을 갖고 있는 하나의 <form>엘리먼트 안에 존재하고 있는 상황이다. 해당 경우에는 server.js 파일 안에 다음과 같은 app.post( ) 라우터를 만들어주면 된다.
// 파일 업로드 input 박스가 여러개일 때
app.post('/upload3', upload.fields([{name: 'upload1'}, {name: 'upload2'}, {name: 'upload3'}, {name: 'upload4'}]), (req, res)=>{
// upload.fields() 미들웨어 사용
// req.files.[name]에 파일에 대한 정보가 담긴다.
console.log(req.files.upload1)
console.log(req.files.upload2)
console.log(req.files.upload3)
console.log(req.files.upload4)
console.log(req.body)
res.send('uploaded')
})
파일 업로드 input 박스가 여러개일 경우에는 upload.fields( ) 미들웨어를 사용한다. 해당 미들웨어의 인자값으로는 배열이 들어가게 되는데 이 배열 안에는 각각의 input 박스의 name값이 객체 형태로 들어간다. 업로드 된 파일의 정보들은 req.files.upload1 , req.files.upload2 ... 와 같이 req.files.[name값] 안에 담기게 된다.
이전에 살펴본 내용들과 함께 미들웨어를 정리해보면 다음과 같다.
- single 파일 업로드 : upload.single( 'input 박스의 name값' )
- multiple 파일 업로드 : upload.array( 'input 박스의 name값' )
- 하나의 form 엘리먼트 안에 여러개의 파일 업로드 input 박스 : upload.fields( [ { name: ' ' }, { name: ' ' }, ... ] )
2. 비동기 파일 업로드
이번에는 axios를 사용해서 비동기 방식으로 파일 업로드를 진행해보려고 한다. axios.html 파일을 새로 만들어서 다음과 같이 <script>를 작성해주도록 하자.
<!-- axios.html -->
<!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>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<h1>Hello Asyncronous multer!!</h1>
<form method="post" action="/upload" enctype="multipart/form-data">
<input type="text" name="subject">
<input type="file" name="upload">
<input type="submit" value="전송">
</form>
<script type="text/javascript">
const frm = document.querySelector('form')
frm.addEventListener('submit', async (e)=>{
e.preventDefault()
// e.target.subject : form 엘리먼트 안에 있는 name="subject"인 input 엘리먼트
// e.target.upload : form 엘리먼트 안에 있는 name="upload"인 input 엘리먼트
const {subject, upload} = e.target
// upload.files[0] : 업로드 파일 정보가 담겨져 있는 객체
// body에 넣을 내용 만들기
const formData = new FormData() // enctype에 있는 포맷으로 변환
formData.append('upload', upload.files[0])
formData.append('subject', subject.value)
const response = await axios.post('/upload', formData)
})
</script>
</body>
</html>
우선 e.preventDefault( )를 통해 'submit' 이벤트를 막아주도록 하자. 그런 다음 e.target.subject 와 e.target.upload를 통해 각각 name="subject" 와 name="upload"인 input 엘리먼트를 가져와서 subject 변수와 upload 변수에 할당한다.
upload.files[0] 을 통해 File 객체를 가져올 수 있는데 File 객체 안에는 업로드 한 파일의 정보들이 담겨있다. FormData( )를 사용하면 File 객체의 내용을 <form>엘리먼트의 enctype에 있는 형태로 치환해줄 수 있다. append( ) 메소드를 이용해 formData 객체 안에 upload.files[0] 데이터를 'upload'라는 이름값으로 , subject.value를 'subject'라는 이름값으로 넣어준다. 이러한 처리를 통해 비동기 요청을 할 때 Request Body에 들어갈 내용들을 만들어 줄 수 있다.
이제 마지막으로 axios.post( '/upload', formData ) 로 요청을 보내주면 된다. ( body 내용을 formData로 전달 )
해당 요청을 받는 라우터는 기존의 app.post( '/upload' , upload.single('upload') , (req, res)=>{ } ) 라우터를 사용해주면 된다.
app.get('/axios', (req, res)=>{
res.render('axios.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')
})
'Node > Express' 카테고리의 다른 글
Node.js - express (19) WebSocket (0) | 2022.03.18 |
---|---|
Node.js - express (17) multer (1) (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 |