[작품] - FormData로 서버에 데이터와 이미지 같이 보내기

1. 개요

음식점을 먹고 난 후 그 식당에 대한 리뷰를 쓰는 기능이 필요했다. 리뷰 기능에는 별점, 음식 사진, 후기 등의 데이터가 있었고 이 모든것을 한번에 서버에 보내 달라는 백엔드의 요청이 있었다. 

지금까지는 문자나 숫자 형식의 데이터만 보냈기 때문에 파일 형식을 어떻게 보낼 지에 대해 많은 생각을 했다. 

 

2. 해결 방법

구글링을 통해 fetch의 헤더를 "multipart/form-data" 형식으로 바꾸는 방식이 있었는데 막상 시도를 하니 클라이언트에서는 잘 보내졌지만 서버에서 못받는 오류가 생겼다. 

 

✅그래서 새로운 방법인 FormData를 이용해 from 생성 후 fetch를 하기로 했다.

 

1️⃣HTML 수정하기

<form class=" reviewBox">
        <div class="modal">
            <div class="modal-title">
                <div class="userName">
                    <span>리뷰 등록</span>
                    <p class="userInfo">작성자:&nbsp;</p>
                    <p class="NameText"></p>
                </div>
                <span class="close">&times;</span>
            </div>
            <div class="modal-contents">
                <fieldset>
                    <span class="text-bold">별점을 선택해주세요</span>
                    <div class="star">
                        <input type="radio" name="reviewStar" value="5" id="rate5"><label for="rate5">★</label>
                        <input type="radio" name="reviewStar" value="4" id="rate4"><label for="rate4">★</label>
                        <input type="radio" name="reviewStar" value="3" id="rate3"><label for="rate3">★</label>
                        <input type="radio" name="reviewStar" value="2" id="rate2"><label for="rate2">★</label>
                        <input type="radio" name="reviewStar" value="1" id="rate1"><label for="rate1">★</label>
                    </div>
                </fieldset>
                <div class="PhotoContent">
                    <div>
                        <img src="" alt="Review_img" class="Review_img">
                    </div>
                    <input type="file" accept="image/*" class="Upload">
                    <p>사진을 올려주세요</p>
                </div>
                <div class="ReviewContent">
                    <textarea required class="content" name="content"
                        placeholder="음식과 서비스에 대한 솔직한 리뷰를 남겨주세요..."></textarea>
                </div>
            </div>
            <div class="modal-foot">
                <input class="ReviewBtn" type="submit" value="등록하기" />
            </div>
        </div>
    </form>

보낼려는 데이터 가장 바깥에 form태그를 넣어서 감싸줬다. 

HTML은 간단했다.

 

2️⃣JS 수정하기

let formData = new FormData();
  formData.append("reviewStar", rating);
  formData.append("photo", file);
  formData.append("content", content);
  formData.append("adminNo", adminNo);

  fetch("http://localhost:4000/file", {
    method: "POST",
    body: formData,
  })
    .then(function (response) {
      if (response.ok) {
        console.log("리뷰가 성공적으로 등록되었습니다.");
      } else {
        console.log("리뷰 등록에 실패했습니다. 다시 시도해주세요.");
      }
    })
    .catch(function (error) {
      console.log("네트워크 오류:", error);
    });
}

const form = document.querySelector(".reviewBox");
form.addEventListener("submit", submitForm);

FormData객체를 생성 후 데이터 각각의 키값을 추가해줬다. FormData는 해당 값을 키/값 쌍으로 구분해준다. 

이후 header에는 아무런 값을 넣지 않았다. 다른 사람들은 header를 만들고 빈 값으로 넣어주던데 header를 아예 안줘도 작동하는 것을 보니 상관없는것 같다. 

body에는 formdata를 그대로 보내주면 해결된다. 

 

마치며

<form action="http://localhost:4000/Review" class=" reviewBox" method="post" enctype="multipart/form-data">

처음에 HTML에서 form 형식을 쓸때 이런 형식으로 썻었다. 백엔드 친구가 form형식에 무조건 enctype를 써야 한다고 해서 이 방식밖에는 없는 것 처럼 보였다. 하지만 문제를 해결하니 없어도 된다는 것을 알았다. 아마 그 친구도 하나의 방식밖에 몰라서 그랬던것 같다. 

 

 let file = fileInput.files[0].name;

그리고 이미지 파일을 보낼 때 처음엔 파일의 주소만 보내면 되는줄 알고 주소만 보냈었다. 하지만 서버 쪽에서 자꾸 오류가 나서 여러 삽질을 해보니 파일 전체를 보내는 것이 정답이였다. 

let file = fileInput.files[0];

현재는 이미지 파일만 보내서 잘은 모르겠지만 다른 파일도 보낼 때 파일 전체를 보내는 것이 아닐까 추측된다. 다음에 기회가 생긴다면 댓글로 후기를 쓸 예정이다.