File Uploads #01

0_CyberLover_0·2022년 4월 27일
0

Node.JS #05

목록 보기
15/19

파일을 업로드 하는 방법을 알아 본다.

업로드 하려면 먼저 로그인이 돼 있어야 한다. 깃허브로 로그인 한다. 그리고 input을 추가한다.

block content
    if errorMessage
        span=errorMessage
    form(method="POST")
        label(for="avatar") Avatar
        input(type="file", id="avatar", name="avatar",accept="image/*")

change-password가 아니라 edit-profile에서 추가해준다. type="file"input을 추가한다.

Avatar라는 label을 먼저 만들고 label(for="avatar")를 입력하고 inputid="avatar"를 추가 해준다.

이 두개가 합쳐져서 클릭하면 아바타를 선택할수 있다. 그리고 avatarname을 줘야 한다.

여전히 formname을 줘야 하기 때문이다. name="avatar"라고 해준다.

사용자가 파일을 선택할수 있는데 pdf같은 파일을 선택 할수도 있다.

모든 이미지 파일만 받아 들일수 있게 해준다. accept="image/*" 를 사용 하면 된다.

어떤 이미지 파일이든 선택할수 있게 되었다.

input을 만드는게 첫 단계이다.

두번째는 이것을 도와줄 middleware를 사용한다.

여기 multer라는 middleware가 있다.

https://www.npmjs.com/package/multer

multer는 파일을 업로드 할수 있게 해준다.npm i multer로 설치해준다.

그리고 multer를 사용법을 알아 본다.

NOTE: Multer will not process any form which is not multipart (multipart/form-data).

"multermultipart가 아닌 form을 처리하지 않는다." 라고 되있다.

multer의 도움을 받고 싶다면 formmultipart form으로 만들어야 한다.

form에다가 enctype="multipart/form-data"를 추가해준다.

block content
    if errorMessage
        span=errorMessage
    form(method="POST", enctype="multipart/form-data")

이렇게 해준건 form이 다르게 encode된다는 의미이다.

이게 파일을 업로드 하기 위한 유일한 조건이다. formmultipart/form-data로 만들어 주면 된다.

이게 파일을 백엔드로 보내기 위해 필요한 encoding type(enctype)이다.

그리고 다음은 middleware를 만들어 줘야 한다.

const upload = multer({ dest: 'uploads/' })
app.post('/profile', upload.single('avatar'), function (req, res, next) {
  // req.file is the `avatar` file
  // req.body will hold the text fields, if there were any
})

middleware를 설정 해주고 이 경우에는 설정과 함께 multer 함수를 사용해서 middleware를 만들고 route에서 사용하는 거다.

먼저 middleware를 만들어 본다. middleware.js에서

export const uploadFiles = multer({ dest: "uploads/" });

여기에서는 req,res를 쓰지 않는다. 대신 multer()를 쓰고 설정한다.

multer에는 configuration object가 있다.

살펴보면 보낼수 있는것 중 하나는 destination이다. 파일을 어디에 보낼지 정한다.

사용자가 파일을 보내면 사용자로부터 파일을 받으면 그 파일을 어딘가에 저장을 해야한다.

예를 들면 하드드라이브 같은 곳 말이다. 나중에는 이게 좋지 않은 이유를 알아 보고

다른 곳으로 저장 시킬거다.

그리고 잊지 말고 multerimport한다.

현재는 파일들을 하드드라이브에 저장해야 된다고 가정하고 진행한다.

const upload = multer({ dest: 'uploads/' })

이 경우에 uploads라는 폴더를 만들고 그리고 multer에게 사용자가 업로드 하는 모든 파일들을 서버의 uploads폴더에 저장하라고 하는거다.

그래서 multer({ dest: "uploads/" })라고 해주었다.

사용자가 보낸 파일을 uploads폴더에 저장하도록 설정된 middleware가 생겼다.

아직 그 폴더가 없어서 에러가 날거다. 폴더를 만들어 준다. (강의에서는 생기던데...)

이제 middlewareroute에 사용한다. controller에는 사용하지 않는다.

route로 이동한다. 그리고 edit-profile에서 사용 해준다.

get이 아니라 post에 사용해 준다. 사용방법을 살펴보면

app.post('/profile', upload.none(), function (req, res, next) {
  // req.body contains the text fields
})

middleware를 쓰고 controller함수를 사용하는거다.

다시 설명하면 url이 있고 middleware, 그리고 controller함수를 쓰는 거다.

이미 url이 있고 post에서 middleware를 사용한다. 그리고 controller함수를 쓰면 된다.

먼저 uploadFiles middleware를 사용한다.

userRouter.get("/logout", protectorMiddleware, logout);
userRouter
  .route("/edit")
  .all(protectorMiddleware)
  .get(getEdit)
  .post(uploadFiles.single("avatar"), postEdit);

uploadFiles.을 써주고 fields,none,single,array등이 있다.

사용자가 다수의 파일을 보내야 될때도 있어서 그렇다.

현재는 하나의 파일만 필요하니 single로 사용해 준다. 그리고 filedName을 써줘야 한다.

formt의 어디에서 파일이 오고 있냐면 avatar에서 오고 있다. 그래서 avatar를 넣어 주었다. 그리고 string이여야 한다.

조금 헷갈릴수 있는데 middleware를 실행한 다음 postEdit을 실행 하는거다.

왜 이렇게 하냐면 multerinput으로 avatar파일을 받아서 그 파일을 uploads폴더에 저장한 다음 그 파일 정보를 postEdit에 전달해 주는거다.

middleware는 왼쪽에서 오른쪽 순서로 작동한다는 걸 기억한다.

multer middleware가 먼저 실행되고 그 다음 postEdit이 실행되는 거다.

다시 한번 정리하면 uploadFiles.single이 하는 역할은 templateinput에서

오는 avatar파일을 가지고 파일을 업로드 하고 uploads폴더에 저장한다.

그리고 다음 controllerpostEdit에 그 파일의 정보를 전달하는 거다.

좋은점은 이렇게 하면 requestreq.file이 추가 된다는거다.

function (req, res, next) {
  // req.file is the `avatar` file

현재는 이미 form datareq.body를 알고 있다. 이제 이걸 사용하기에

userRouter.get("/logout", protectorMiddleware, logout);
userRouter
  .route("/edit")
  .all(protectorMiddleware)
  .get(getEdit)
  .post(uploadFiles.single("avatar"), postEdit);

이 코드가 req.file을 사용하게끔 해주는 거다.

사용자가 urlform을 보내면 middleware를 걸쳐서 middleware는 사진을 시스템에 저장하고 , req.file을 추가 할거다.

그리고 나서 controller를 실행시키면 req.filereq.body를 사용 할수 있다.

현재 controller는 이미 req.body를 사용하고 있다.

하지만 아직 req.file이 어떻게 생겼는지는 모른다.

export const postEdit = async (req, res) => {
  const {
    session: {
      user: { _id },
    },
    body: { name, email, username, location },
    file,
  } = req;
  console.log(file);

콘솔을 이용해서 확인해 본다. 에러가 없다. 아직 파일을 사용하고 있지 않지만

있어서 나쁠건 없다. 파일을 업로드 하면 어떤일도 발생하지 않지만 콘솔을 확인해 보면

file을 볼수 있다. 파일 경로도 나온다. 파일명은 랜덤은로 만들어 졌다.

원본 파일명도 나온다. type도 있고, destination도 있고, 파일명과 경로로 있다.

이제 uploads폴더를 확인해 본다. 살펴보면 현재 파일은 jpeg 같은 확장자가 없다.

그래도 브라우저는 이해하기 때문에 상관없다. 파일을 업로드 하는데 성공 했다.

req.file을 사용할수 있는 이유는 userRouter를 보면 postEdit전에 Multer를 사용하고 있다. 반대였다면 postEdit에서 req.file을 사용할수 없다.

middleware의 순서는 아주 중요하다.

userRouter.get("/github/start", publicOnlyMiddleware, startGithubLogin);
userRouter.get("/github/finish", publicOnlyMiddleware, finishGithubLogin);

예를 들어 사용자가 /github/start에 가면 먼저 middleware가 확인하고 다음으로 가는 거랑 같은 거다.

이것도 마찬가지이다. middleware를 확인하고 finishGithubLogin으로 가는거다.

다시 한번 정리하면 single은 하나의 파일만 업로드 한다는거고 파일의 input namemiddleware에 전달해야 한다.

nameformname이랑 같아야 한다.

path: 'uploads/2ec71c2270a855b3e422a370e005d5b3'

이제 경로(path)로 사용할거다. modelsUseravatarUrl이 있다.

avatarUrl이 바로 이 경로인건다.

profile
꿈꾸는 개발자

0개의 댓글