본문 바로가기

백엔드/nodeJS

File Upload - multer middleware

* multer packages

 

multer

Middleware for handling `multipart/form-data`.. Latest version: 1.4.5-lts.1, last published: a year ago. Start using multer in your project by running `npm i multer`. There are 3850 other projects in the npm registry using multer.

www.npmjs.com

파일을 업로드할 수 있게 도와주는 패키지이다. 예를들어 아바타 이미지를 업로드하려고 할 때 사용하면된다.

 npm i multer 

 

* multer 사용방법

STEP 1.

multer를 사용하려면 form의 형태를 multipart form으로 만들어줘야한다. 일반적인 form의 형태는 처리하지 않는다.

multipart form을 만들기 위해서는 multipart/form-data 을 form에 붙여준다. (파일을 백엔드로 보내기 위해 필요한 encoding type === enctype)

 multipart/form-data 

form(method="POST" enctype="multipart/form-data")

 

STEP 2.

multer 함수를 사용해서 middleware를 만들어야한다.(import 필수) 미들웨어를 만들 때 지금까지와 다르게 req,res 사용하지 않고 multer()를 사용하고 설정한다. 미들웨어를 통해서 할 수 있는 사항은 업로드한 파일을 어디로 저장할 것인지 설정할 수 있다.

예를 들어 사용자가 보낸 파일을 하드드라이브에 저장할 수 있다. ( 이 방법은 추천하지 않는다!) 지금은 하드드라이브에 저장으로 진행한다. 

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

사용자가 보낸 모든 파일을 서버 하드드라이브에 저장한다. 이때 지정해준 uploads 파일이 있는지 확인해야 한다.


multer 미들웨어를 사용할 때 업로드 용량을 설정하는 옵션이 있다. 용량은 bytes 기준으로 작성한다. limits:{fileSize:bytes}
export const avatarUpload = multer({
  dest: "uploads/avatars/",
  limits: { fileSize: 3000000 },
});​

 

 

STEP 3.

만든 미들웨어를 필요한 라우터에서 사용해주면 된다. 지금은 프로필 에디터를 POST 하기 전에 사용자가 선택한 이미지를 저장해야 한다. user router에서 postEdit 전에 미들웨어가 발동하면 된다.

 

 순서 : URL / middleware / controller함수

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

 

 미들웨어 적용순서 : 미들웨어이름.파일수("필드네임")

 

* 파일수 : 사용자가 다수의 파일을 보낼 때  사용할 수 있다. (single, arrary...)

* 필드네임 : input("type="file"의 name") 값은 string

 

uploadFiles.single의 역할 : 템플릿 input에서 오는 파일을 업로드하고 uploads 폴더에 저장한 다음 파일의 정보를 POST Edit로 전달한다. 그래서 req.file로 해당 파일에 접근할 수 있다.

컨트롤러에 req.file을 추가하고 확인해보면 정상적으로 파일이 업로드 된 것을 확인할 수 있다. 이때 업로드된 파일은 jpg, png의 확장자가 아닌 브라우저만 이해할 수 있는 형식으로 uploads 폴더에 저장된다.

 

console.log(file) 결과화면

결과화면에서 path가 avatar url에 사용될 경로이다. (user model에 avarar url이 있다.)

 

잠깐! 사용자가 아바타를 바꾸지 않고 다른 사항만 변경하게 되면 기존 등록된 아바타를 undefine으로 저장될 수 가 있다. 또 한 file: {path} 로 경로를 바로 지정할 경우에도 백엔드에서 path 값을 확인 하지 못해 에러가 발생한다. 해결하기 위해서는 uesr. session에서 avatarUrl 값을 불러온 뒤 if-else로 해결해 주면된다.

if(file===true) avatarUrl = file.path else { avatarUrl = avatarUrl }
삼항연산자 : file ? file.path : avatarUrl

 

DB에는 파일 저장하지 않는다! 폴더에 파일을 저장하고 DB에서는 그 파일의 위치만 저장한다.

 


정상적으로 작동하면 파일을 불러와볼까?

 

    img(src=loggedInUser.avatarUrl,width="100px", height="100px")

템플릿에서 img를 불러오면 사진이 뜨지 않는다. 이유는 경로! 현재 이미지는 uploads/#### 위치에 저장되어 있는데 템플릿에서 불러온 이미지는 상대url : users/edit/uploads/###### 로 불러온다. 그래서 이미지 위치 앞에 "/" + 추가해준다.

    img(src="/" + loggedInUser.avatarUrl,width="100px", height="100px")

짜짠!

그래도 안나온다. 해당 경로를 라우터로 만들지 않아서 인식하지 못한다. /uploads 경로의 라우터를 만들어 주고 브라우저에게 폴더를 개방하여 위치를 알려줘야 한다. (Static Files Serving)

브라우저에게 폴더 위치를 알려주는 방법은 express.static("노출하고자하는 폴더이름") 사용하면된다.

app.use("/uploads", express.static("uploads"));

 


<문제점>

#1. 업로드한 모든 사진이 uploads 폴더에 저장되고 있다.

#2. 서버에 파일을 저장하고 있다.

 ㄴ 서버는 업데이트 되거나 죽으면 서버에 저장된 파일들이 삭제된다.

-> 서버가 재시작되도 파일이 안전하게 보관할 수 있도록 다른 곳에 저장해야 한다. (아마존의 하드드라이브 같은 곳에)

반응형

'백엔드 > nodeJS' 카테고리의 다른 글

connect-mongo (cookie, session, env)  (0) 2023.07.23
Sessions and Cookies  (0) 2023.07.23
브라우저 Status Code  (0) 2023.07.16
express (6) - GET / POST  (0) 2023.06.25
express (5) - absolute / relative URL  (0) 2023.06.25