-
Notifications
You must be signed in to change notification settings - Fork 0
multipart
‘펀잇’에는 편의점 음식을 먹고 리뷰를 작성할 수 있는 폼이 있다.
사용자는 리뷰에 사진, 별점, 태그, 리뷰 내용, 재구매 의사를 남길 수 있다.
이 과정에서 이미지 파일을 서버로 보낼 때 문제가 생긴다.
어떤 문제가 생기는지 알아보자.
이미지는 File 형태이다.
<input ref={inputRef} type="file" accept="image/*" onChange={handle} />
보통 위의 형식처럼 input type을 file로 주면 파일 업로드를 할 수 있다.
이렇게 file을 서버로 전송하면 해당 file 데이터를 multipart/form-data
형태로 받게 된다.
우리가 생각하는 ‘파일이름.확장자’ 형식이 아닌 이진 데이터 형식으로 받는다.
이제 File 형태의 이미지와 내용을 한 번에 서버로 보내보자.
이때, formData 객체를 통해 보낼 수 있다.
formData란 form 데이터를 동적으로 생성하고 전송할 수 있는 객체이다.
append()를 사용해 내용을 key와 value 형식으로 보낼 수 있다.
formData.append('image', reviewImageFile, reviewImageFile.name);
이 formData를 사용해 데이터를 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을 안 적으면 해결될까?
웁스. 아니다.
이젠 이런 오류가 발생한다.
왜 이런 오류가 발생할까?
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',
});
작성 성공!!!
- 📚 프론트엔드 개발 문서
- 🌏 브라우저 지원 범위
- 🧪 프론트엔드 테스트 전략
- [웹 접근성] a tag와 button의 차이는 무엇일까?
- multipart
- SvgSprite 컴포넌트 사용하기
- [INFRA] 프론트엔드 CI/CD 구축
- [기술 검토] 리액트 쿼리 도입 이유
- [기술] 로그인 기능 도입기
- 🐛 S3 배포 캐싱 오류
- 이미지를 위한 S3와 Cloudfront 설정하기
- 📓 성능리포트 ‐ 펀잇 서비스 최적화하기
- 펀잇 SEO 개선하기
- 📚 백엔드 개발 문서
- intellij에서 private DB 연결하기
- [INFRA 0] 전체 infra 구조 - ver1
- [INFRA 1] infra 서버 세팅
- [INFRA 2] 백엔드 CI/CD 구축
- [INFRA 3] 백엔드 DB 연결
- [INFRA 4] 깃허브 PR 라벨을 기준으로 젠킨스 빌드하기
- [LOG] 로그 세팅
- [Trouble Shooting] 일관된 테스트 격리 적용하기
- [Trouble Shooting] 프록시로 동작하는 @Transactional, 전파 옵션 관리