form
을 통해 유저가 파일을 업로드 후 POST
보내는 형식이 아닌, navigator.mediaDevices
를 이용한 웹 상의 즉석 동영상 레코더로 찍은 파일을 자동으로 보내는 것이라 이래저래 많이 해맸다.
form
에 넣어 fetch
하기.완전히 잘못된 방법이었다. JS 오브젝트는 말 그대로 JS 내에서만 공유되는 문법이지, 서버나 form 이 이해할 수 없다. 그래서 데이터를 단순 문자열로 변환하는 JSON 이 쓰이는 것. 아무튼 호기로운 첫 시도는 아래와 같았다.
await fetch("/videos/upload-from-recorder", {
method: "POST",
headers: {"Content-Type": "multipart/form-data},
body: {
"title": ~,
"video": video file
"thumbnail": image file
}});
구글링을 통해 headers
를 이래저래 바꿔보고, 파일에 Blob
을 넣기도, createObject
를 이용한 url 을 넣기도 해보았지만 서버 쪽에서 리퀘스트만 받고, form
은 정상적으로 전달되지 않았다.
1번 방식의 문제점을 깨달은 뒤, 어떻게 form
에 데이터를 묶어 보낼지 고민하다 생각한 방법. 문자열로만 이루어진 데이터를 JSON 으로 변환해 fetch
하는 법은 알았지만, 당연히 같은 방식으론 파일을 보낼 수 없었다.
두번째 시도는 아래와 같다.
var form = document.createElement("form");
form.setAttribute("charset", "UTF-8");
form.setAttribute("method", "Post");
form.setAttribute("action", "/videos/upload-from-recorder");
var video = document.createElement("input");
hiddenField.setAttribute("type", "hidden");
hiddenField.setAttribute("name", "video");
hiddenField.setAttribute("value", video File);
...
form.appendChild(video);
document.body.appendChild(form);
form.submit();
input
을 하나하나 form
에 모두 넣어준 뒤 submit
했다. 결과는 30% 정도 성공. 서버에서 form
을 받을 수는 있었다. 다만, input
세팅을 잘못한 건지 보낸 Blob
이나 파일의 url 을 정상적으로 처리하지 못했다.
form
의 enctype
을 수정하기도 하고, 파일 형식도, input
세팅도 계속 바꿔보며 삽질했지만 파일이 제대로 처리되지 않아 좌절했다.
1번과 2번의 조합이라고 할 수 있겠다. document
내 가상 form
이 아닌 JS 내부에 form
을 만들고 fetch
했다.
파일 유형과 헤더 세팅, express
라우터에서 multer
설정 등 수많은 시행착오 후 제대로 파일을 받아냈다. 너무 기뻤다. 결과는 아래와 같다.
①
const form = new FormData();
form.enctype = "multipart/form-data";
// fetch headers 에 multipart 를 주면 form 을 제대로 받지 못했다. 여기서 한참 해멨다.
form.append("video", video file, "video.mp4);
// createUrl 을 이용한 url 이 아닌 video Blob 을 그대로 보냈다.
form.append("thumbnail", thumb file, "thumb.jpg");
// 마찬가지로 Blob 그대로
...
await fetch("/videos/upload-from-recorder", {
method: "POST",
headers: {
//"Content-Type": "multipart/form-data",
},
// headers 를 비워준다.
body: form
// body 엔 JS object 가 아닌 form 을 그대로 보낸다.
});
② 두 개 이상의 파일을 보내기 때문에 express
라우터에서 multer
세팅을 해준다.
router.post("/videos/upload-from-recorder", multer({dest: "uploads"}).fields([
{name: "video", maxCount: 1},
{name: "thumbnail", maxCount: 1}
]), controller);
③ multer
이용해 받은 파일은 Controller
에서 다음과 같이 처리한다.
export const controller = async(req, res) => {
const { video, thumbnail } = req.files;
const { title, ... } = req.body;
// video 와 thumbnail 이 array 에 담겨오기 때문에 video[0].path 로 Blob 의 url 을 가져올 수 있다.
도무지 원인을 알 수 없는 에러를 잡을 때에 비해 즐거운 삽질이었다. 과정에서 많이 배우기도 했으며 이런저런 시도 끝에 성공했을 때의 기쁨은 덤.
벽에 부딪는 과정을 늘 즐기려 한다. 화이팅 👾
한음님 안녕하세요,
정말 감사드립니다. 덕분에 이미지 업로드 해결했습니다!
정말정말정말 감사감사감사드립니다.
새해 복 많이받으시고 하시는 일들 모두다 만사형통하시길 바라겠습니다!!! ㅠㅠ