app.use(express.urlencoded({ extended: true }));
app.use(express.json());
req.body
를 읽으려면 얘가 필요하다. (post전송 시)npm install multer
package.json
에 multer가 설치 된 것 확인.npm install multer@^1.4.4
const multer = require("multer"); // multer 불러오기
enctype
을 꼭 multipart/form-data
로 설정해주어야 한다!multipart/form-data
가 아닌 폼에서는 동작하지 않는다!<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"); // multer 불러오기
const path = require("path"); //내장 모듈이다. 경로를 쉽게 구하기 위한.
const upload = multer({
dest: "uploads/", //파일을 업로드하고, 파일이 저장 될 경로를 지정하는 속성이다.destiny.
});
single()
, array()
, fields()
req.file
or req.files
이라는 객체를 생성해서 다음 함수에 넘겨주게 된다.upload.single()
을 사용한다. 얘는 req.file
을 생성하게 된다
// upload라는 부분의 post요청에 single() 미들웨어를 걸고 싶은 것.
//single("")미들웨어 안에는 client가 파일 객체를 넘겨주는 식별자가 들어간다.
//미들웨어로 넘겨주는 값은 input type="" name="" 의 name부분을 적어준다.
//single()은 미들웨어이다. 얘는 cilent가 보낸 요청 중에 userfile 이라는 name의 파일이 있다면?
//파일을 저장해서 multer의 조건에 맞게 저장을 한다. (client의 파일 업로드에서 지정한 const upload = multer)
//저장 후 req.file 이라는 객체를 만든다. 그리고 다음에 위치한 함수에 넘겨준다.
//여기서는 function (req, res)에 넘겨주게 되는 것.
//그럼 파일은 req.file에서 볼 수 있다.
app.post("/upload", upload.single("userfile"), function (req, res) {
console.log("file:", req.file);
console.log("body:", req.body);
res.send("파일 업로드");
});
req.file
객체와 req.body
객체를 확인할 수 있다.//path는 특정 파일 경로를 받았을 때, 그에 대한 관리나 조작을 도와준다.
//예를 들어 확장자를 추출하든지, 파일이름을 알아온다든지!
const path = require("path");
//extname 메소드로 확장자를 알 수 있고
//basename 메소드로 파일명을 알 수 있다.
console.log("hi.txt의 확장자:", path.extname("hi.txt"));
console.log("hi.txt의 이름:", path.basename("hi.txt", path.extname("hi.txt")));
//기본 구조
const uploadDetail = multer({
//diskStorage() .디스크에 저장소를 만들어 둘 때 사용하면된다. 객체가 들어간다.
storage: multer.diskStorage({
destination: function(){
},
filename: function(){
}
})
})
//-------------------------------------이렇게 세부 설정!
//---------multer 설정 상세 구조에는 storage와 limits 두 객체가 들어간다. 아래 구조.
//storage : 파일을 저장할 정보.
//--diskStorage : 파일을 디스크에 저장하기 위한 기능을 제공하는 메소드. 그걸 어케 할거냐. 아래 두개로
//-----destination : 파일이 저장 될 경로
//-----filename : 파일이 저장 될 이름
//diskStorage() .디스크에 저장소를 만들어 둘 때 사용하면된다. 객체가 들어간다.
//여기에는 3개의 인자가 들어간다. done이라는 콜백함수도 들어간다. 여기에 파일경로를 넣어준다.
//설정을 끝마치면 done이 실행된다. 얘를 이용해서 경로를 지정하는 것. done뒤에 오는 것이 경로다.
//그리고 파일 업로드를 계속 하게 되면 덮어쓰기가 잘못 될 수 있으니
//Date.now() 함수를 사용해 파일명에 활용해보자.
const upload = multer({
dest: "uploads/",
});
const uploadDetail = multer({
storage: multer.diskStorage({
destination: function (req, file, done) {
done(null, "uploads/");
},
filename: function (req, file, done) {
console.log("uploadDetail filename", req.body);
console.log(file); // file.originalname: 쿼카.png 라면?
const ext = path.extname(file.originalname); // .png 출력.
const basename = path.basename(file.originalname, ext); // 쿼카 출력.
const fileName = basename + "_" + Date.now() + ext; // 쿼카_123453156.png 출력.
done(null, fileName); //이렇게 파일명 내맘대로 설정하기 완료.
},
}),
limits: { fileSize: 5 * 1024 * 1024 }, //5MB 제한.
//limits:파일을 제한하겠다.
//filesize : 파일의 최대 크기 지정가능.
});
//-------------------------------------그리고 불러오자
app.post(
"/upload/detail",
uploadDetail.single("userfile"),
function (req, res) {
console.log("file detail:", req.file);
console.log("body detail:", req.body);
res.render("result", {
src: req.file.path,
title: req.body.title,
});
}
);
//[index.ejs파일]
<h2>multer storage를 이용한 설정</h2>
<form action="/upload/detail" method="post" enctype="multipart/form-data">
<input type="file" name="userfile" /><br />
<input type="text" name="title" /><br />
<button type="submit">업로드</button>
</form>
array()
array()
메소드를 이용한다. 하나의 input을 이용한다. name 하나로 여러개의 파일을 받는 방법req.files
를 생성하게 된다.//[index.js파일]
app.post("/upload/array", uploadDetail.array("userfile"), function (req, res) {
console.log("file 여러개(ver1):", req.files);
res.send("여러개 업로드 성공!");
});
//[index.ejs파일]
<h2>파일 여러개 업로드 (하나의 input 이용)</h2>
<form action="/upload/array" method="post" enctype="multipart/form-data">
<!-- input type file의 multiple 속성은 여러개의 파일을 선택할 수 있게 함. -->
<input type="file" name="userfile" multiple /><br />
<input type="text" name="title" /><br />
<button type="submit">업로드</button>
</form>
console.log(req.files);
를 확인해보면 정보도 잘 들어와 있다! fields()
fields()
메소드를 이용한다. input이 2개 이상 일 때 이용한다. (name이 2개 이상)req.files
를 생성하게 된다.//[index.js파일]
app.post("/upload/fields",uploadDetail.fields([{ name: "userfile1" }, { name: "userfile2" }]),
function (req, res) {
console.log("file 여러개(ver2):", req.files);
console.log("req.body", req.body);
res.send("여러개 업로드 성공(ver2)");
}
);
//[index.ejs파일]
<h2>파일 여러개 업로드 (여러 개의 input 이용)</h2>
<form action="/upload/fields" method="post" enctype="multipart/form-data">
<input type="file" name="userfile1" multiple /><br />
<input type="text" name="title1" /><br />
<input type="file" name="userfile2" /><br />
<input type="text" name="title2" /><br />
<button type="submit">업로드</button>
</form>
☑️ 헷갈리지 말자
지금까지 한 건 일반 폼 전송! 동기 http 통신!
그리고 이제 할 건 동적 폼 전송! 비동기 http 통신!
<button *type*="button" *onclick*="axiosGet()">axios get 전송</button>
이런식으로 함수를 걸어서 js로 폼 전송을 적용시켜준다.
axios({
method: "GET",
url: "/axios",
params: data
}).then((response) => {
//서버가 제공한 응답(데이터)
console.log(response.data)
//서버 응답의 HTTP 상태 코드. 성공이면 200
console.log(response.status)
//서버가 응답한 헤더
console.log(response.headers)
});
url
: 통신하고자 하는 주소를 넣어준다.method
: 통신하고자 하는 방식을 넣어준다.data
: json형태의 보내고자 하는 데이터를 {}
안에 넣어준다.{ key: value, key: value}
의 형태로 만들어 준다.req.body
로 데이터를 보낸다.params
: get 요청으로 데이터를 보낼 때 url의 ?
뒤에 객체로 보내지는 부분을 넣어준다.{ key: value, key: value}
의 형태로 작성한다.req.query
에 데이터가 담긴다.params
값을 안보낼거면 URL에 쿼리스트링을 작성해서 보내도 된다.//[index.js파일]
//비동기 http 통신(동적 폼 전송) axios
app.post("/upload/dynamic",uploadDetail.single("userfile"),function (req, res) {
//응답으로 잘 나오는지보려고 보낸거.
res.send({ src: req.file.path });
}
);
//[index.ejs파일]
<h2>동적 폼 전송(axios)를 이용한 파일 업로드</h2>
<form name="dynamic-upload">
<input type="file" name="userfile" /><br />
<input type="text" name="title" /><br />
<button type="button" onclick="dynamicUpload()">업로드</button>
</form>
<div id="dynamic-upload-result"></div>
//[index.ejs파일 - script 부분]
<script>
function dynamicUpload() {
const form = document.forms["dynamic-upload"]
const formData = new FormData();
//FormData객체의 append메소드는 데이터를 추가할 때 사용한다.
formData.append("title", form.title.value) //얘는 값을 받아 올 수 있다.
//type이 file인 input태그를 선택해서 files에 접근해보면 파일이있다?
//아래 얘네 2줄로는 처리못한다. 이미지데이터는 files로 접근해야한다!
console.log("value", form.userfile.value)
console.log("files", form.userfile.files)
//파일이라는 정보 자체를 넘겨주는 것.
formData.append("userfile", form.userfile.files[0])
//아래 방식은 이미지 데이터를 정상적으로 처리할 수 없음
// const data = {
// title: form.title.value,
// userfile: form.userfile.value
// }
axios({
method: "post",
url: "/upload/dynamic",
data: formData, //폼데이터를 여기로 옮긴다.
headers: {
"Content-type": "multipart/form-data"
}
}).then((res) => {
console.log(res.data)
const result = document.getElementById("dynamic-upload-result")
result.innerHTML = `<img src="/${res.data.src}" width="150"/>`
})
}
</script>
이렇게 복잡하고 헷갈리는 multer 끝!
많이 쓰일 것 같은 multer. 하지만 나중에 사용할 때 마다 찾아보고 사용할 것 같다. 꽤나 헷갈린다!