# 8.6 - 8 File Upload in user profile edit- avatar

이원규·2022년 7월 3일
0

Itube

목록 보기
30/46
post-custom-banner

File Upload

1. avatar 업로드(multer이용)

1.1 views (edit-profile)

//추가
form(method="POST", enctype="multipart/form-data")//multer middleware 때문에 multipart form으로 만듦.
	label(for="avatar") Avatar
	input(type="file", id="avatar")

1.2 middleware 설치 및 미드웨어 만들기 - Multer

-> 파일을 업로드하도록 도와주는 미드웨어.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
    Multer는 주로 파일 업로드에 사용되는 multipart/form-data를 처리하기 위한 node.js 미들웨어입니다.
    주의! Multer는 multipart(multipart/form-data)가 아닌 form을 처리하지 않습니다.
    npm i multer
    enctype="multipart/form-data"
    https://www.npmjs.com/package/multer

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/ 파일을 만들어야함.
  • gitignore
/uploads

1.3 multer middleware - Router에 적용

  1. userRouter.js
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형태로)전달해주는 역할을 함.

이 저장할 때는, 파일명이 랜덤 파일명으로 바뀜.

1.4 userController - postEdit 수정

  1. userController - postEidt
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로 업로드 해준다.

-> 중요한 것! : 절대 DB에 파일을 저장하지 말고, 파일은 폴더에 저장하고 DB에는 파일의 경로(path)만 저장해라 !

  • 엄밀하게 말하면 뭐든지 다 쌓아놓는 곳은 하드, 혹은 웹하드, AWS에서는 S3에 해당하는 것이고 데이터베이스는 문자, 테이블, 시트로 표현할 수 있는 것이라고 합니다.
    따라서 데이터베이스 자체에는 이미지를 저장할 수 없기 때문에 경로만 저장해두며 해당 경로에 있는 이미지를 별도로 찾게 되는 것으로 이해했습니다.

2. view에 아바타 사진 나타내기(Static File)

  • view: edit-profile.pug
//추가
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고고)

2.1 Static files serving 설명 및 사용

-> 이 때, 브라우저가 서버의 어떤 폴더로든 다 갈 수 있다면, 보안상 좋지 않을 것임. 그래서 우리가 브라우저게에 어떤 페이지와 폴더를 볼 수 있는지 알려줘야함. 그러기 위해서 static files serving이라는 걸 활성화 시킬 것임. 폴더 전체를 브라우저에게 노출시킨다는 뜻임.

  • express.static(multer가 파일 저장한 폴더명(root), [options])

Express에 내장된 미들웨어 기능입니다. 정적 파일을 제공하며 serve-static을 기반으로 합니다. root 인수는 static asset을 제공할 root 디렉토리를 지정합니다. 이 함수는 req.url을 제공된 root 디렉토리와 결합하여 제공할 파일을 결정합니다.

  1. server.js:
//추가 -> 이거 한 줄이면 사진이 뜰 것임, 역할: 위의 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);

-> 이렇게 해주면 이제 브라우저에도 사진이 뜰 것임.

3. 문제점

우리가 파일을 서버에 저장한다는 것임.(upload파일이 서버에 있음 nomad-wetube)

-> 하나의 백엔드에 두 개의 서버를 사용할 떄도 있는데, 그러면 파일을 공유하기도 뭐함. 서버가 죽으면 서버를 시작할 수 있는 코드를 가지고 다른 서버에서 시작하면 되는데 글케되면 이전 서버에 저장한 파일들은 날라감.
-> 나중에 서버가 아닌 곳에 저장하도록 파일 저장 위치를 바꿀 것임. 이건 나중에 실제 서버 배포할 때, 수정할것임.

profile
github: https://github.com/WKlee0607
post-custom-banner

0개의 댓글