[Vue] Form Data로 첨부파일 전송할 때 주의사항

🌙

회원가입을 하고 내 정보 수정 페이지를 진행하면서 프로필 사진을 업로드하는 기능을 구현하고 있다.

프로필 사진을 누르면 로컬 폴더에 저장된 사진을 선택해 변경할 수 있다.

 

SSR 프로젝트에서는 form 태그에 사진, 닉네임, 이메일 등 정보를 담고 POST 요청을 보냈다.

컨트롤러에서는 Multipartfile 타입으로 데이터를 받고, 파일을 정적 저장소에 저장했다.

하지만 REST API에서는 폼 태그를 통해 요청을 보내는 것이 불가능하며, 모든 요청은 Axios를 통해 이루어진다.

닉네임이나 이메일처럼 문자열 타입의 데이터를 보낼 때에는 요청 바디에 넣어서 전송하는 간단한 방식이었지만 같은 방식으로 파일 데이터를 전송하는 것은 불가능하다.

Rest Controller에서 Multipartfile로 데이터를 받으려면 어떻게 해야할까?

Form Data

폼데이터는 자바스크립트에서 웹 폼 데이터를 동적으로 생성, 조작하기 위해 사용하는 객체이다.

HTML의 <form> 태그와 유사한 방식으로 데이터를 생성하고 전달할 수 있어, 비동기통신에서 유용하게 사용된다.

사용자 입력 데이터 뿐만 아니라 파일 업로드와 같이 복잡한 데이터도 처리할 수 있다.

사용방법

생성하기

  • new 연산자를 통해 객체를 생성한다.
const formData = new FormData();

데이터 추가

  • append()를 통해 데이터를 키와 값의 형식으로 저장한다.
  • 전자는 필드명, 후자는 실제 데이터 값이다.
formData.append("nickname", this.nickname);

파일 추가

  • 파일 추가 역시 append()를 사용한다.
  • 파일 태그에서 files 요소를 꺼내 값에 지정한다.
formData.append("uploadFile", this.$refs.uploadImage.files[0]);

// modifyPage.vue
<input type="file" accept="image/*" ref="uploadImage">

데이터 전송

  • 헤더의 Content-type을 multipart/form-data로 지정한다.
axios.post("/user/modify", formData, {
    headers: {
        "Content-Type": "multipart/form-data",
    },
}).then(() => {});

주의사항

데이터 타입

정확하진 않지만, 파일을 제외한 모든 데이터를 문자열로 받는듯하다.

Date 타입의 생일 속성에 <input type="date"> 데이터를 넣었더니 String을 Date 타입으로 파싱할 수 없다는 에러가 발생했다.

null 삽입

null을 삽입해 요청을 보내도 스프링에서 null 체크를 하지 못한다.

파일의 경우 첨부하지 않으면 null 값으로 보내져서 NullPointException이 뜨기도 했는데..

문자열의 경우 때려죽여도 null 체크를 못했다.

 

분명 요청을 보내기 직전까지만 해도 undefined로 나와있는 gender

하지만 스프링에서 로그를 찍어보면 null도, 빈 문자열도 아닌 undefined가 뜬다 😳

이게..자바에 있다고?

 

gender==null, gender.isNull(), gender.isEmpty() 등 갖은 시도를 해보았지만 true가 출력된 적은 단 한번도 없었다.

혹시 null이라는 문자열이 들어간게 아닐까?

gender.upperCase()을 찍어보았다.

진짜 null이 들어가벌인 것이었다;;;;;;;황당그잡채

 

프사 업로드나 성별 설정에서 null 체크가 필요했던 상황인지라 이것저것 시도해보았는데, 결국은 아래와 같이 바꿔야만 했다.

Before

폼데이터 객체에 값을 냅다 담는다.

formData.append("gender", this.gender);

After

gender가 undefinednull인지 확인하고, 아닌 경우에만 폼데이터 객체에 담는다.

if(this.gender) {
    formData.append("gender", this.gender);
}

🤦

폼데이터 미친놈...

2시간동안 삽질하다가 겨우 해결했다!!!!!!