* 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 폴더에 저장된다.


결과화면에서 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 |