
모델 회원가입을 마무리 하려고 민서가 만들어둔 데이터를 서버에 전달하는 것을 내가 맡아서 하던 중이었다.
나는 그대로 POST 요청을 했는데 어랍쇼? 자꾸 에러가 났다
그래서 스웨거를 확인해봤다

multipart/form-data 이게뭔데.. 먼저 multipart가 무엇인지 알아보자
클라이언트와 서버 간에 전송되는 HTTP 요청 또는 응답에서 여러 종류의 데이터를 동시에 전송하기 위해 사용되는 방식이다
일반적으로 파일 업로드와 관련된 데이터를 전송하는데 주로 사용된다
멀티파트 요청은 'Content-Type' 헤더에 'multipart/form-data' 값을 가지며 여러개의 파트(part)로 구성된다. 각 파트는 개별적인 데이터 조각으로 파일이나 텍스트 데이터 등을 포함할 수 있다. 각 파트는 헤더와 본문(body)으로 구성되어 있으며 헤더에는 파트의 메타 데이터가 포함되어 있고 본문에는 실제 데이터가 포함된다.
<input
type="file"
accept="image/*"
onChange={(e) => {
uploadImg(e);
}}
/>
formData는 form 필드와 그 값을 나타내는 일련의 key/value 쌍을 쉽게 생성할 수 있는 방법을 제공한다.
new FormData() 를 통해 빈 객체를 만들 수 있고 FormData.append 을 사용하여 key/value 쌍을 추가할 수 있다
그런데 민서의 코드는 이렇게 돼있었다.
const imgUrl = URL.createObjectURL(imgObj[0]);
위처럼 URL로 한다고 하더라도 blob:localhost ~~… 이런식으로 나오고 있었다 서버에서 s3이미지 url을 가져와서 보내는 형식이 아니라면 우리는 File을 그대로 보내줘야 하는 것이다.
profileImg를 formData 객체로 선언하고 넣어준 다음 회원가입에 필요한 데이터와 함께 requestBody에 넣어주고 Content-type은 multipart/form-data로 설정해줬다. 그래서 서버에서는 MultiPart형식의 이미지 url을 받아야하는데 계속 [Object FormData]형식으로 받았다
알고 보니 그렇게 하는 것이 아니었고 reaquestBody를 FormData 형식으로 넘겨줘야 하는 것인데 이렇게 하니까 designerInfo 데이터를 서버에서 읽을 수가 없었다 이걸 어떻게 처리해야할까,,,
우리가 보내야 할 데이터 profileImg와 designerInfo는 완전히 다른 Content-type이다. 두 종류의 데이터가 하나의 HTTP Request Body에 들어가야 하는데, 한 Body에서 이 2 종류의 데이터를 구분에서 넣어주는 방법이 필요하다. 그래서 우리는 multipart 타입을 사용해야하는 것이다.
결론부터 말하자면 FormData 객체로 만들어주고 이 객체에 profileImg 파일과 designerInfo json데이터를 넣어줬다. 그리고 이 객체를 reaquestBody로 넣어줬다!
const requestBody = new FormData();
const jsonSignUpData = JSON.stringify(signUpData);
const deisgnerInfo = new Blob([jsonSignUpData], { type: 'application/json' });
requestBody.append('designerInfo', deisgnerInfo);
requestBody.append('profileImg', profileImg.file);
🤯 그러다가 갑자기 의문이 들었다... 저걸 왜 json으로 바꿔줘야하지?
우리가 평소에 보내는 requestBody는 JavaScript 객체이다. 우리가 따로 변환해서 보내지 않았다. 그렇다면?
일반적으로 JavaScript 객체가 제공되면 이 객체는 내부적으로 JSON 문자열로 변환되어 HTTP 요청 본문에 포함됩니다.
🤯 그렇다면 여기서 Blob이 뭐지?
Blob 객체는 파일류의 불변하는 미가공 데이터를 나타냅니다. 텍스트와 이진 데이터의 형태로 읽을 수 있다
아하!! 그래서 JSON 형태를 유지해서 서버에서 읽을 수 있겠구나...
🤯 그렇다면 File은? 왜 그냥 넣어준거지?
File 객체는 Blob의 한 종류로, Blob을 사용할 수 있는 모든 맥락에서 사용할 수 있습니다.
✨ 최종 코드
const postDesignerSignUp = async () => {
const signUpData: DesignerInfo = {
name: name.data,
gender: gender.data,
...
};
const requestBody = new FormData();
const jsonSignUpData = JSON.stringify(signUpData);
const deisgnerInfo = new Blob([jsonSignUpData], { type: 'application/json' });
requestBody.append('designerInfo', deisgnerInfo);
requestBody.append('profileImg', profileImg.file);
try {
const data = await api.post('/auth/signup/designer', requestBody, {
headers: {
'Content-Type': `multipart/form-data`,
},
...
};
};
네트워크 메서드가
FormData객체를 바디로 받는다는 건FormData의 특징입니다. 이때 브라우저가 보내는 HTTP 메시지는 인코딩되고Content-Type속성은multipart/form-data로 지정된 후 전송됩니다.
헉 그럼 header content 타입도 설정안해줘도 되나?????
const data = await api.post('/auth/signup/designer', requestBody);

왕 ! 성공 ~~!!!! 🥳🥳🥳🥳
나와 함께 이 문제를 해결한 우리 멋쟁이 서버리드 안현주씨의 아티클 ~ ㅋㅋ 볼람볼 ~
https://hellozo0.tistory.com/414
저는 이거 실패했었는데 추후에 이 글을 보고 다시 도전해보겠습니다. 이런 글 작성해주셔서 너무너무 고맙습니다!!