💡 body-parser 는 데이터를 쉽게 처리할 수 있게 도와주는 라이브러리였지만, 멀티파트 데이터를 처리하지 못한다
는 단점이 있다. -> multer
이용
<input type = "file">
로 지정post
방식으로 해야한다. <form action="" method="" enctype="multipart/form-data"></form>
💡 Multer는 multipart/form-data
가 아닌 폼에서는 동작하지 않는다.
파일 업로드를 위해
사용되는 미들웨어(1) 터미널에서 multer설치
npm install multer
(2) 작성하고 있는 js파일에 multer 불러오기
✅ 이때 multer도 원하는 이름으로 생성!!
const multer = require('multer')
(3) js파일에서 업로드 경로 설정
✅ dest : 파일을 업로드하고 그 파일이 저장될 경로를 지정
하는 속성
✅ 이때, uploads or upload는 원하는 파일명으로 지정
const upload = multer({
dest : 'uploads/',
});
const uploadDetail = multer({
//storage : 저장할 공간에 대한 정보
//diskStorage : 파일을 저장하기 위한 모든 제어기능 제공(파일 저장관련 설정)
storage: multer.diskStorage({
//destination : 업로드할 파일을 저장할 폴더를 지정
destination(req, file, done) {
done(null, 'uploads/'); //에러처리 : null(설정하지 않음), done은 콜백함수
},
//filename : 파일이름 결정(요청객체, 업로드된 파일 객체, 콜백함수 순서)
//여기서 file은 index.ejs에서 정의한 함수(본인이 설정한 이름으로 기재)
filename(req, file, done) {
//extname() : 확장자를 추출
const ext = path.extname(file.originalname);
//basename() : 파일이름을 추출(파일의 오리지널명, 확장자) => 확장자를 제외해서 파일이름만 추출
const newName = path.basename(file.originalname, ext) + Date.now() + ext;
done(null, newName); //콜백함수 호출
},
}),
//limits : 파일저장, 용량제한
limits: { filesize: 5 * 1024 * 1024 },
});
storage
: 저장할 공간에 대한 정보diskStorage
: 파일을 디스크에 저장하기 위한 모든 제어 기능을 제공destination
: 저장할 경로filename
: 파일명limits
: 파일 제한fileSize
: 파일 사이즈 제한 <h1>FORM 싱글연습</h1>
<!-- 파일업로드때는 post방식 -->
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="userfile" /><br />
<input type="text" name="title" /><br />
<button type="submit">업로드</button>
</form>
const multer = require('multer');
const path = require('path'); //폴더와 파일의 경로를 쉽게 조작하도록 제공
//multer 설정
const upload = multer({
//dest : 업로드할 파일을 저장할 폴더를 지정
//이렇게 하게되면 자동적으로 폴더가 생성이 됌
dest: 'uploads/',
});
//router
app.get('/', (req, res) => {
res.render('index');
});
//post.(multer설정이름.하나보내는거라 single.('보내야할 파일이름') ~~~)
//single()
app.post('/upload', uploadDetail.single('userfile'), (req, res) => {
console.log('file', req.file); //req.file : 파일 업로드 성공 결과(파일 정보)
console.log('title', req.body); // req.body : title 데이터 정보 확인 가능
});
-> 터미널에서 req.file
,req.body
들의 객체 확인이 가능하다.
-> 실행을 하면 uploads/ 폴더가 새로 생기고, 세부설정을 했기 때문에 위에서 보여지는 것처럼 객체들의 파일명이 변경된 것을 확인할 수 있다.
array()
: 여러 파일을 업로드할 때 사용, 하나의 요청 안에 여러 개의 파일이 존재
<h1>FORM 멀티 연습(ver1)</h1>
<form action="/upload/array" method="post" enctype="multipart/form-data">
<input type="file" name="userfiles" multiple /><br />
<input type="text" name="title" /><br />
<button type="submit">업로드</button>
</form>
const multer = require('multer');
const path = require('path'); //폴더와 파일의 경로를 쉽게 조작하도록 제공
//multer 설정
const upload = multer({
//dest : 업로드할 파일을 저장할 폴더를 지정
//이렇게 하게되면 자동적으로 폴더가 생성이 됌
dest: 'uploads/',
});
app.post('/upload/array', uploadDetail.array('userfiles'), (req, res) => {
console.log('file', req.files); //req.fules: [{},{},{},...] 배열 형태로 각 파일 정보를 가짐, 업로드 된 파일이 여러개이므로 복수형태로 작성!!!
console.log('title', req.body); //req.body : title 데이터 정보 확인 가능
});
📝 req.files
: 업로드 되는 파일이 여러개이고, 배열 형태로 가지기 때문에 files과 같이 복수형태로 작성
+ 업로드 될때의 세부설정은 (1-4)에서 작성한 그대로이다.
fields()
: 여러 파일을 업로드할 때 사용, 하나의 요청이 아닌 여러 개의 요청이 들어올 때 사용<h1>FORM 멀티연습 (ver2)</h1>
<!-- 하나의 요청이 아닌 여러 개의 요청이 들어올 때 -->
<form action="/upload/fields/" method="post" enctype="multipart/form-data">
<input type="file" name="userFile1" /><br />
<input type="text" name="title1" /><br />
<input type="file" name="userFile2" /><br />
<input type="text" name="title2" /><br />
<button type="submit">업로드</button>
</form>
//multi ver2
app.post('/upload/fields', uploadDetail.fields([{ name: 'userFile1' }, { name: 'userFile2' }]), (req, res) => {
console.log('file', req.files);
console.log('title', req.body);
});
🧡 multer 요약
req.file
- 파일 하나, 업로드 된 파일req.body
- 나머지 정보, 파일 외에 데이터 값들하나의 요청 안에 여러 개의 파일이 존재할때
req.files
- 파일 n개req.body
- 나머지 정보하나의 요청이 아닌 여러개의 요청이 들어올 때
req.files
- 파일 n개req.body
- 나머지 정보<h1>동적 파일 업로드</h1>
<form>
<input type="file" id="userfile" /><br />
<input type="text" id="title" /><br />
<button type="button" onclick="fileUpload()">업로드</button>
</form>
<br />
<br />
<div class="resultBox"></div>
<script>
const resultBox = document.querySelector('.resultBox');
function fileUpload() {
const file = document.querySelector('#userfile');
//파일에 접근하기 위해서 file.files[0]을 사용
//file.files는 배열을 반환하며 우리가 원하는 것은 첫번째 요소이기 때문에 [0]를 해줌
console.log(file.files[0]);
//FormData : 자바스크립트 내장 객체이고 폼 데이터를 생성해줌
const formData = new FormData();
formData.append('title', document.querySelector('#title').value);
formData.append('file', file.files[0]); //file은 가장 마지막에 써야함. 위에다가 일반데이터를 써주고 파일은 마지막!!!!
axios({
method: 'post',
url: '/upload/axios',
data: formData,
headers: {
'Content-Type': 'multipart/form-data', //동적업로드할때 비동기에는 form에 넣어줬지만 동적에선 꼭 여기에서 넣어줘야한다.
},
}).then((res) => {
console.log('res', res);
resultBox.innerHTML = `<p> 이름은 ${res.data.title.title}</p><img src = ${res.data.file.path} width = "300px" height = "300px">`; //html에 바로 보여지게 지정하고 css도 설정할 수 있다.
});
}
</script>
➡️ append 할 때, file은 가장 마지막에 작성할 것!
➡️ append(key, value)
- key 자리에는 차피 백엔드로 보내는거니까 이름 상관없다.
➡️ FormData
: 자바스크립트 내장 객체이고 폼 데이터를 생성해준다.
// 동적
//single('프론트에서 보내는 key로 했던 파일명') =>> formData.append('file', file.files[0]); 이부분
app.post('/upload/axios', uploadDetail.single('file'), (req, res) => {
console.log('file', req.file);
res.send({ file: req.file, title: req.body });
});
<h1>프로필 - 일반폼 전송</h1>
<form action="/upload" method="post" enctype="multipart/form-data">
<fieldset>
<legend>프로필 작성</legend>
<input type="text" name="id" placeholder="아이디" /><br />
<input type="password" name="pw" placeholder="비밀번호" /><br />
<input type="text" name="name" placeholder="이름" /><br />
<input type="number" name="age" placeholder="나이" /><br />
<input type="file" name="userFile" /><br />
<button type="submit">업로드</button>
</fieldset>
</form>
<h4>프로필</h4>
<img src="<%= file%>" width="300px" height="300px" />
<span><p><%= userInfo.id%>님 환영합니다!</p> </span><br />
<span>비밀번호 : <%= userInfo.pw%></span><br />
<span>이름 : <%= userInfo.name%></span><br />
<span>나이 : <%= userInfo.age%></span>
➡️ <%= %> 여기에 백엔드에서 보내주는 파일을 받으면 되는 것!
const express = require('express');
const multer = require('multer');
const path = require('path');
const app = express();
const PORT = 8000;
app.set('view engine', 'ejs');
app.use(express.urlencoded({ extended: true }));
//정적파일설정
app.use('/uploads', express.static(__dirname + '/uploads'));
const upload = multer({
//dest : 업로드할 파일을 저장할 폴더를 지정
//이렇게 하게되면 자동적으로 폴더가 생성이 됌
dest: 'uploads/',
});
const uploadDetail = multer({
storage: multer.diskStorage({
destination(req, file, done) {
done(null, 'uploads/');
},
filename(req, file, done) {
const ext = path.extname(file.originalname);
const newName = req.body.id + ext; //확장자명 : id+확장자
done(null, newName);
},
}),
//limits : 파일저장, 용량제한
limits: { fileSize: 5 * 1024 * 1024 },
});
app.get('/', (req, res) => {
res.render('index');
});
app.post('/upload', uploadDetail.single('userFile'), (req, res) => {
console.log('file', req.file);
console.log('title', req.body);
res.render('result', { title: '프로필', userInfo: req.body, file: req.file.path }); //여기서 파일도 같이 보내줘야함
});
app.listen(PORT, () => {
console.log(`http://localhost:${PORT}`);
});
다양한 방법으로 동일한 문제를 풀어보았다. 파일 업로드 방식은 매우 중요하니 활용해서 사용할 수 있게 한 문제를 다양하게 푸는 방법을 공부해야 할 것 같다.