Youtube Clone Coding (6. multer을 사용하여 file upload하기)

LeeJaeHoon·2021년 10월 25일
0
post-thumbnail
  1. npm i multer

  2. form에 enctype="multipart/form-data"을 써줘야함.

  3. input에 file을 가져올때 accept="image/*을 써줘야 이미지 파일이 아닌 다른 파일을 업로드하지 못하게 막을 수 있음.

    input(type="file", id="avatar", name="avatar", accept="image/*")
  4. export const uploadFile = multer({ dest: 'uploads/' })을 middleware 파일에 저장한다.

    dest: "uploads/"는 user에게 form으로 받은 file정보가 uploads라는 파일 밑에 저장된다는 뜻이다.

    따라서 uploads라는 파일을 만들어주어야 한다. (위 코드작성시 알아서 uploads파일이 만들어 지기는 한다.)

  5. uploadFile middleware을 쓸곳에 import한후 middleware으로 넣어준다.

    • single 메소드는 하나의 파일만 전달 받는다는 뜻
    • input에서 가져오는 파일 name이 avatar이어서 uploadFile.single("avatar")이라고 작성한다.
      userRouter
        .route("/edit")
        .all(protectedMiddleware)
        .get(getEdit)
        .post(uploadFile.single("avatar"), postEdit);
  6. 위 middleware을 작성하면 req.file을 사용할 수 있다.

    export const postEdit = (req, res) => {
    	const {file} = req;
    	console.log(file);
    }
    • 사용자가 file을 upload하고 나면 req.file에 업로드한 파일의 정보가 들어가고 uploads폴더에 filenam이 저장됨.
    • 밑의 코드는 콘솔로 찍어본 req.file의 내용
      {
        fieldname: 'avatar',
        originalname: '7B629FCD-E340-46E6-A801-D65B357DF7C8.jpeg',
        encoding: '7bit',
        mimetype: 'image/jpeg',
        destination: 'uploads/',
        filename: '4ad5113a7819a1cec775e3ef9b61b1d9',
        path: 'uploads/4ad5113a7819a1cec775e3ef9b61b1d9',
      }
    • user가 file을 업로드 하지 않을 경우 현재 user의 avatarUrl을 담는다.
    • user가 file을 업로드 할 경우 req.file.path를 findByIdAndUpdate에서 avartarUrl에 담는다.
      • database에 파일전체가아니라 파일경로만 저장해야함!
        export const postEdit = async (req, res) => {
          const pagetitle = "Edit Profile";
          const {
            session: {
              user: { _id, avatarUrl },
            },
            body: { name, email, username, location },
            file,
          } = req;
          if (req.session.user.email !== email) {
            const existEmail = await User.exists({ email });
            if (existEmail) {
              return res.status(400).render("edit-profile", {
                pagetitle,
                errorMessage: "이미 있는 이메일 입니다.",
              });
            }
          }
          if (req.session.user.username !== username) {
            const existUsername = await User.exists({ username });
            if (existUsername) {
              return res.status(400).render("edit-profile", {
                pagetitle,
                errorMessage: "이미 있는 username 입니다.",
              });
            }
          }
          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");
        };
    • 위의 코드로 image를 업로드 했을때 image파일 경로에 에러가 뜸
      • 이유: avatarUrl로 req.file.path를 담았는데 req.file.path의 내용은 다음과 같음
        • path: 'uploads/4ad5113a7819a1cec775e3ef9b61b1d9'
        • 서버에있는 uploads파일을 브라우저에서 열지못하기 때문에 image경로에 에러가 발생 하는 것임.
        • 이를 해결하기 위해선 서버에서 브라우저가 uploads폴더에 접근 할 수 있게 설정 해주어야함.
          • 밑의 코드로 인해 브라우저가 서버에있는 uploads폴더에 접근 할 수 있음.

          • 누군가 만약 /uploads로 가려고 한다면, uploads폴더의 내용을 보여주는 코드

            app.use("/uploads", express.static("uploads")); 
    • edit-profile.pug
      • user가 github로 로그인시 이미 avatarUrl이 존재하므로 pug에서 img를 보여줄때 경로를 다르게 설정 해 주어야 함.
        if loggedInUser.avatarUrl.startsWith("upload")
            img(src=`/${loggedInUser.avatarUrl}`,width="100",height="100")
        if loggedInUser.avatarUrl.startsWith("http")
            img(src=loggedInUser.avatarUrl,width="100",height="100")
  7. multer 을 사용하여 video upload하기

    • middleware설정
      • user가 video를 업로드 하려 할때 fileSize가 너무 크면 안되므로 fileSize에 제한을 준다.
      • 단위는 메가바이트이다.
        export const videoUpload = multer({
          dest: "uploads/videos/",
          limits: {
            fileSize: 20000000,
          },
        });
    • videoRouter에 middleware넣기
      videoRouter
        .route("/upload")
        .all(protectedMiddleware)
        .get(getUpload)
        .post(videoUpload.single("video"), postUpload);
    • postUpload controller에 req.file.path로 video의 경로 가져오기
      export const postUpload = async (req, res) => {
        const {path: fileUrl} = req.file;
        const { title, description, hashtags } = req.body;
        try {
          await Video.create({
            title,
            description,
            fileUrl,
            hashtags: Video.formatHashtags(hashtags),
          });
          return res.redirect("/");
        } catch (error) {
          return res.status(400).render("upload", {
            pageTitle: `Upload Video`,
            errorMessage: error._message,
          });
        }
      };
    • watch.p에 video tag넣기
      • video(src= /${video.fileUrl}, controls)
  8. 문제점

    • 우리가 파일을 서버에 저장한다는것
      • 서버가 죽으면 코드와 업로드된 파일들이 있다면, 파일은 날라가기 때문.

0개의 댓글