샘플로 쓸 영상을 하나 다운로드 해놨다.
여기서 쉽게 구할수 있다. 실험할 용량과 형식에 맞게 구할 수 있다.
이제 video
를 업로드 할 거다. video
에는 파일이 필요하다.
먼저 views
폴더의 upload.pug
에 들어가서
block content
if errorMessage
span=errorMessage
form(method="POST")
label(for="video") Video File
input(type="file", accept="video/*",requried,id="video",name="video")
video
에 쓸 label
을 만든다. file
로 해도 상관없다.
그리고 Video File
을 추가한다. 아래에는 type
이 file
인 input
을 만든다.
accept
에는 모든 종류의 video
형식을 쓴다. required
를 추가해주는 걸 잊지 않는다.
label
은 id
를 활용하니까 꼭 id
를 추가해준다. 그리고 multer middleware
사용을 위해 name
을 추가한다. video
를 써줬다.
새로고침을 해보면 영상 파일을 선택하지 않으면 업로드 하지 못한다.
그리고 샘플 영상을 첨부해서 업로드를 해준다.
그러기 전에 controller
에 어떤 일이 생길지 안다.
videoRouter
코드를 수정 해준다.
videoRouter
.route("/upload")
.all(protectorMiddleware)
.get(getUpload)
.post(uploadFiles.single("video"), postUpload);
여기에 만들어 놓은 uploadFiles middleware
를 추가 해준다.
그리고 form
에서 file
의 name
을 추가하는걸 잊어선 안된다.file
의 name
은 video
이다.
이제 multer documenatation
에서 볼게 있다.
https://www.npmjs.com/package/multer
추가적으로 보낼수 있는 option
들이 있다. 이 옵션들 중에 fileSize
라는걸 사용할거다.
이걸 가지고 2개의 middleware
에서 avatar
파일의 업로드 용량을 1MB
이하로 하고
video
파일의 업로드 용량을 10MB
이하로 제한하면 좋을것 같다.
사람들이 용량이 큰 영상을 올리지 않게 말이다.
그래서 이 방법 대신에 2개의 middleware
를 만든다.
export const avatarUpload = multer({
dest: "uploads/avatars/",
limits: {
fileSize: 3000000,
},
});
export const videoUpload = multer({
dest: "uploads/videos/",
limits: {
fileSize: 10000000,
},
});
하나는 avatar
업로드 하는걸로 만든다. uploads/avatars
에 저장하도록 만든다.
다른 하나는 videoUpload
로 만든다. 그리고 uploads/videos
에 저장하도록 한다.
그리고 두곳 모두 limits
를 추가한다. avatar
,video
의 limits
는 fileSize
를 쓴다.
그리고 각각 용량을 설정해 주었다. 기본(단위)으로 바이트로 설정되어 있다.
이제 이보다 용량이 큰 파일은 업로드 되지 않는다.
테스트를 해본다. 일단 avatarUpload
의 fileSize
를 아주 작게 해본다.
3000바이트로 하면 어떻게 되는지 테스트 해보겠다.
새로고침을 하였더니 그전에 에러가 발생하였다. middelware
이름을 변경해서 그런것 같다.
userRouter
에 들어가보면 더 이상 존재하지 않는 uploadFiles
를 사용중이다.
import {
protectorMiddleware,
publicOnlyMiddleware,
avatarUpload,
} from "../middlewares";
userRouter
.route("/edit")
.all(protectorMiddleware)
.get(getEdit)
.post(avatarUpload.single("avatar"), postEdit);
변경한 이름으로 변경 해준다.
그리고 videoRouter
의 uploadFiles
도 존재하지 않으니까
import { protectorMiddleware, videoUpload } from "../middlewares";
videoRouter
.route("/upload")
.all(protectorMiddleware)
.get(getUpload)
.post(videoUpload.single("video"), postUpload);
videoUpload
로 변경해준다. 이제 콘솔에서 확인해 보면 에러가 나지 않는다.
새로고침하고 설정한 용량보다 큰 avatar
를 업로드하면 어떻게 되는지 시도해 본다.
파일이 너무 크다고 에러가 났다. 파일이 너무 커서 multer
가 허용하지 않고 있다.
이제 이 오류를 사용자에게 제대로 된 메세지로 보여줘야 한다.
그래서 응답을 보내줘야 하는데 나중에 해주기로 한다.
어찌되었든 fileSize limits
는 잘 작동하고 있다.
이제 2개의 middleware
가 생겼다. 하나는 용량 제한으로 video
를 업로드하는거고
다른 하나는 avatar
를 업로드 하는거다.
videoController.js
에서
export const postUpload = async (req, res) => {
const file = req.file;
const { title, description, hashtags } = req.body;
try {
await Video.create({
title,
description,
fileUrl: file.path,
hashtags: Video.formatHashtags(hashtags),
});
이제 file
을 받아서 그리고 file
자체가 아니라 file
의 경로를 원하니까 fileUrl
을 추가하고 file.path
을 넣어준다.
multer
는req.file
을 제공해주는데file
안에path
가 있다는걸 기억한다.
하지만 아직 video
안에 fileUrl
을 만들지 않았다.
Video.js
에서
const videoSchema = new mongoose.Schema({
title: { type: String, required: true, trim: true, maxLength: 80 },
fileUrl: { type: String, reqired: true },
file
없이는 video
를 만들지 못한다. 그리고 테스트 해보기 전에 잊으면 안될게 있다.
upload.pug
에서
block content
if errorMessage
span=errorMessage
form(method="POST", enctype="multipart/form-data"
multer
을 사용해서 파일을 업로드 하고 싶다면 form
의 encoding type
을 바꿔 줘야 한다.
edit-progfile
의 form
에 enctype
을 추가한 것처럼 똑같이 해주면 된다.
이 작업을 해주지 않으면 multer
는 정상 작동하지 않는다.
잘못된 코드를 찾아 헤매도 찾지 못할거다. 그러니 enctype
이 multipart/form-data
인지 꼭 확인하도록 한다.
이제 테스트해 본다. 업로드에 성공했다. DB
에서도 video
를 찾을수 있다.
db.videos.find({})
쳐보면 fileUrl
이 uploads/videos/파일이름
이 나온다.
그리고 uploads
폴더에 들어가면 avatars
와 videos
가 있다.
이전 파일들이 지워지지 않는 문제가 있긴 하다.
multer
를 사용해서 uploads
폴더 안 서로 다른 디렉토리에 저장할수 있게 만들었다.
avatars
와 videos
폴더가 있다. 현재 avatars
에는 아무것도 없는데 새로운 avatar
를 업로드 하면 생길거다.
이제 업로드한 영상을 재생시켜 본다.
업로드된 영상을 클릭해 보면 예전에 만든대로 id
를 가지고 비디오를 찾고 있다.
그리고 video
의 데이터가 모두 있다. 이제 여기에 video element
를 추가하면 될것 같다.
watch.pug
로 가서 video element
를 추가한다.
watch.pug
는 videoController
가 render
하고 있는 template
이다.
videoControlloer.js
에서
export const watch = async (req, res) => {
const { id } = req.params;
const video = await Video.findById(id);
if (!video) {
return res.status(404).render("404", { pageTitle: "Video not found." });
}
return res.render("watch", { pageTitle: video.title, video });
};
DB
에서 video
를 찾은 다음 그 video
를 변수로 보내고 있다.
이 말은 object
가 통째로 template
에 있다는 거다.
이제 다시 돌아가서 video.fileUrl
을 쓴다.
watch.pug
에서
block content
video(src="/" + video.fileUrl)
그리고 path
때문에 작동하지는 않을거다. 그래서 path
도 추가해 주었다.
새로고침해서 확인하면 영상이 올라온걸 확인 할수 있다. 여기서 이제 controls
를 추가해준다.
block content
video(src="/" + video.fileUrl,controls
그러면 이제 controls
가 생겼고 재생이 된다.
다시 한번 되짚어 보겠다.
middleware
를 만들어 봤고 limits
설정하는것도 했다. avatar
와 video
에 각각 원하는 용량으로 제한하면 된다.
watch.pug
에서 video
도 추가해봤다. 그리고 영상이 실제로 존재하니까 fileURL
도 추가해 주었다.
uploadVideo
로는 영상을 업로드하고 있다.
그리고 path
를 바로 꺼내고 path
을 쓸수 있게 변경 해주었다.
videoController.js
에서
export const postUpload = async (req, res) => {
const { path } = req.file;
const { title, description, hashtags } = req.body;
try {
await Video.create({
title,
description,
fileUrl:path,
hashtags: Video.formatHashtags(hashtags),
});
그리고 다른 방법은 request.file.path
가 있다는 것을 알고 있다.
이것 자체를 바꿀수는 없지만 path
를 req.file.path
에서 받은뒤
이름을 fileUrl
로 바꿀수 있다.
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),
});
그러면 이렇게 바꿀수 있게 된다. 이게 바로 ES6
의 힘이다.