//추가
form(method="POST", enctype="multipart/form-data")//multer middleware 때문에 multipart form으로 만듦.
label(for="avatar") Avatar
input(type="file", id="avatar")
-> 파일을 업로드하도록 도와주는 미드웨어.multer npm
npm i multer
-> 조건: multer를 사용하려면 form을 multipart form으로 만들어줘야함.(NOTE: Multer will not process any form which is not multipart) -> 이 말 뜻은 우리 폼이 기존 form과 다르게 encod될 거란 뜻임. 이게 파일을 백엔드로 보내기 위해 필요한 encode type임.
form(method="POST", enctype="multipart/form-data")
multer(opts)
dest 또는 storage: 파일을 저장할 위치
fileFilter: 허용되는 파일을 제어하는 함수
limits: 업로드된 데이터의 한계
preservePath: 기본 이름 대신 파일의 전체 경로 유지
사용 예시
const multer = require('multer')
const upload = multer({ dest: './public/data/uploads/' })
app.post('/stats', upload.single('uploaded_file'), function (req, res) {
// req.file is the name of your file in the form above, here 'uploaded_file'
// req.body will hold the text fields, if there were any
console.log(req.file, req.body)
});
.single(fieldname)
이름이 fieldname인 단일 파일을 수락합니다.
단일 파일은 req.file에 저장됩니다.
-> 만들기:
1. middleware.js
import multer from "multer";
export const uploadFiles = multer({dest: "uploads/"})// dest: 사용자가 업로드한 파일을 uploads/파일에 저장하라고 해주는 것임. 따라서 폴더 내에 uploads/ 파일을 만들어야함.
/uploads
import { protectorMiddleware, publicOnlyMiddleware, uploadFiles } from "../middlewares";
userRouter.route("/edit").all(protectorMiddleware).get(getEdit).post(uploadFiles.single("avatar") ,postEdit);// post일 때만 uploadFiles 미드웨어 작동하고, .single("field name") : 파일을 하나만 저장한다는 뜻이고, 이 파일의 input name을 fieldname칸에 넣엊줘야함. .이렇게 하면 req에 req.file이 추가될 거임. req.file is the `avatar` file
-> multer: input으로 avatar파일을 받아서 그 file을 uploads/ 폴더에 저장한 다음, 그 파일 정보를 postEidt에다가 (req.file형태로)전달해주는 역할을 함.
이 저장할 때는, 파일명이 랜덤 파일명으로 바뀜.
const { session: {user: {_id, avatarUrl}}, body: { name, email, username, location}, file} = req;
console.log(file);
const updateUser = await User.findByIdAndUpdate(_id, {
avatarUrl: file ? file.path :avatarUrl,// 만약 req.file이 있다면(아바타를 업로드해줬다면) file.path를 이용해 업로드된 파일을 아바타로 사용하고, 그게 아니라면 기존의 avatarUrl즉, 기존의 아바타 파일을 업로드 해주라는 뜻임.
// 최종 코드
export const postEdit = async (req, res) => {
const { session: {user: {_id, avatarUrl}}, body: { name, email, username, location}, file} = req;//여기서 body는 업데이트 된 정보.
//onsole.log(file);-> 없으면 undefined로 뜰 것임
if(req.session.user.email !== email || req.session.user.username !== username){
const existEmail = await User.exists({email});
const existUsername = await User.exists({username});
if(existEmail || existUsername){
return res.render("edit-profile",{pageTitle:"Edit Profile",errorSpan:"that email/username is already used"});
}
}
const updateUser = await User.findByIdAndUpdate(_id, {
avatarUrl: file ? file.path :avatarUrl,
name,
email,
username,
location,
},
{new:true}
);
req.session.user = updateUser;
return res.redirect("/users/edit");
};
-> 파일을 업로드 하고, 폼의 submit을 해주면 다음과 같은 콘솔창이 나타남.
여기서 path는 model의 avatarUrl에 넣을 것임.
-> 글구 multer가 이런 밑의 사진처럼 uploads 폴더에 파일을 저장함.
-> 처음 import에서 file:{path}안해준 이유: path를 해버리면, 만약 프로필 수정할 때 아바타 파일 업로드 안하게 되면 오류가 나서 이렇게 file만 import해주고, 업로드 할 때는 file.path로 업로드 해준다.
//추가
block content
img(src="/" + loggedInUser.avatarUrl, width=100, height=100)
-> src에 /를 붙여준 이유: 원래 req.session.user의 avatarUrl은 uploads/b51d39e70a6031a3785b9b494a308021인데 /를 안 붙이면 상대 url이 되어버려서 /users/uploads/~~가 돼버림. 따라서 /를 붙여줘서 절대 url주소로 바꿔준 것ㅇ임.
-> 여기서 이미지는 여전히 안 보일 것임. 여기서 파일 주소 :http://localhost:4000/uploads/b51d39e70a6031a3785b9b494a308021
이렇게 뜨는데, 여기에 대한 Router를 안 만들어줬음. ㅋㅋ 라우터 만들기 ㄱ ㄱ(2.1고고)
-> 이 때, 브라우저가 서버의 어떤 폴더로든 다 갈 수 있다면, 보안상 좋지 않을 것임. 그래서 우리가 브라우저게에 어떤 페이지와 폴더를 볼 수 있는지 알려줘야함. 그러기 위해서 static files serving이라는 걸 활성화 시킬 것임. 폴더 전체를 브라우저에게 노출시킨다는 뜻임.
Express에 내장된 미들웨어 기능입니다. 정적 파일을 제공하며 serve-static을 기반으로 합니다. root 인수는 static asset을 제공할 root 디렉토리를 지정합니다. 이 함수는 req.url을 제공된 root 디렉토리와 결합하여 제공할 파일을 결정합니다.
//추가 -> 이거 한 줄이면 사진이 뜰 것임, 역할: 위의 url로 가면 url을 보여주는 것이 아니라, 그 파일을 보여주라고 시키는 것임.
app.use("/uploads", express.static("uploads"));
//최종
app.use(localsMiddleware);
app.use("/uploads", express.static("uploads"));
app.use("/",rootRouter);
app.use("/videos",videoRouter);
app.use("/users",userRouter);
-> 이렇게 해주면 이제 브라우저에도 사진이 뜰 것임.
-> 하나의 백엔드에 두 개의 서버를 사용할 떄도 있는데, 그러면 파일을 공유하기도 뭐함. 서버가 죽으면 서버를 시작할 수 있는 코드를 가지고 다른 서버에서 시작하면 되는데 글케되면 이전 서버에 저장한 파일들은 날라감.
-> 나중에 서버가 아닌 곳에 저장하도록 파일 저장 위치를 바꿀 것임. 이건 나중에 실제 서버 배포할 때, 수정할것임.