multipart
‘펀잇’에는 편의점 음식을 먹고 리뷰를 작성할 수 있는 폼이 있다.
사용자는 리뷰에 사진, 별점, 태그, 리뷰 내용, 재구매 의사를 남길 수 있다.
이 과정에서 이미지 파일을 서버로 보낼 때 문제가 생긴다.
어떤 문제가 생기는지 알아보자.
📁 File Upload
이미지는 File 형태이다.
<input ref={inputRef} type="file" accept="image/*" onChange={handle} />
보통 위의 형식처럼 input type을 file로 주면 파일 업로드를 할 수 있다.
이렇게 file을 서버로 전송하면 해당 file 데이터를 multipart/form-data형태로 받게 된다.
우리가 생각하는 ‘파일이름.확장자’ 형식이 아닌 이진 데이터 형식으로 받는다.
📚 FormData
이제 File 형태의 이미지와 내용을 한 번에 서버로 보내보자.
이때, formData 객체를 통해 보낼 수 있다.
formData란 form 데이터를 동적으로 생성하고 전송할 수 있는 객체이다.
append()를 사용해 내용을 key와 value 형식으로 보낼 수 있다.
formData.append('image', reviewImageFile, reviewImageFile.name);
이 formData를 사용해 데이터를 multipart/form-data 형식으로 보낼 수 있다.
🧑🦲 Content-type: multipart/form-data
form에 내용을 모두 작성하고 제출을 눌러보자.
작성한 데이터들은 Body에 넣어 HTTP Request로 서버에 전송된다.
이때, Body의 타입을 명시하는 것이 Content-type Headers이다.
기본적으로 form을 전송하면 Content-type은 application/x-www-form-urlencoded 이다.
그런데 우리는 이미지를 내용과 함께 전송해야 한다.
이미지는 file 형태이고, 내용은 json 형태로 둘의 Content-type이 다르다.
다른 종류의 데이터를 하나의 HTTP Request Body에 넣어야 한다면 어떻게 구분할 수 있을까?
이때, multipart 타입을 통해 해결할 수 있다.
multipart란 다양한 형태의 콘텐츠를 함께 전송할 때 사용하는 방법이다.
그럼, Content-type을 multipart/form-data로 지정하면 될까?
🚨 에러 발생
웁스. 아니다.
위와 같은 오류가 발생한다.
왜 이런 오류가 발생할까?
기본적으로 formData에 파일이 있을 경우 브라우저는 자동으로 boundary를 붙여준다.
그런데 Content-type을 설정해 주면 이게 Override 되어 boundary가 사라지게 된다.
그래서 위와 같은 오류가 발생하게 된 것이다.
그렇다면 Content-type을 안 적으면 해결될까?
🚨 에러 발생2
웁스. 아니다.
이젠 이런 오류가 발생한다.
왜 이런 오류가 발생할까?
formData를 전송할 때, 이미지 이외의 내용은 JSON.stringify 처리를 했다.
const 내용 = {
rating,
tagIds,
content,
rebuy,
};
const 내용json변환 = JSON.stringify(내용);
서버에 데이터를 보낼 때, 데이터는 문자열 형태여야 하기에 객체를 문자열로 인코딩 한 후 전송해야 한다.
따라서 JSON.stringify() 를 사용하여 객체를 JSON 문자열로 변환했다.
여기서 json 데이터를 application/json 타입으로 명시해 주지 않아 octet-stream(8비트 단위의 이진 데이터)으로 인식하게 된 것이다.
이는 'Blob(Binary Large Object)'을 통해 해결할 수 있다.
Blob은 이름 그대로 바이너리 형태로 큰 객체를 저장할 수 있다.
아까 JSON.stringify()한 JSON 문자열을 Blob 처리해 보자.
const jsonBlob = new Blob([내용json변환], { type: 'application/json' });
Blob 처리를 하면 JSON 문자열을 이진 데이터로 변환해 준다.
type에 application/json 을 명시하여 데이터가 JSON 유형임을 알려준다.
이렇게 Blob 처리된 내용을 formData에 넣어준다.
formData.append('reviewRequest', jsonBlob);
그리고 body에 formData를 실어 POST로 보내면
const response = await fetch(url, {
method: 'POST',
body: formData,
credentials: 'include',
});
작성 성공!!!
'펀잇' 카테고리의 다른 글
[🐛트러블슈팅] 토스트를 구웠는데 먹을 수 없다구요?!?! (2) | 2023.10.19 |
---|---|
펀잇을 성능 개선해보자 (2) | 2023.10.15 |
2차 데모데이 피드백과 반영 (0) | 2023.10.14 |
1차 데모데이 피드백과 반영 (2) | 2023.08.30 |
우아한테크코스 프로젝트 기획 (0) | 2023.08.13 |
댓글