웹/React

React Axios Post FormData - 이미지랑 JSON 같이 보내기 (에러 엄청 난 후기)

공대생철이 2022. 11. 23. 22:23
728x90

현재 사용하고 있는 기술 스택은 Next.js이다.

 

Tailwind CSS, Styled Component도 쓰는데 스타일링 관련이니깐 잠깐 제끼자.

const [menuImage, setMenuImage] = useState("");
    
<input
	className='hidden text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 cursor-pointer dark:text-gray-400 focus:outline-none dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400'
	id='file_input'
	type='file'
	onChange={(event) => {
		let reader = new FileReader();
		if (event.target.files[0]) {
			reader.readAsDataURL(event.target.files[0]);
		}
		reader.onloadend = () => {
			const resultImage = reader.result;
			setMenuImage(resultImage);
		};
	}}
/>

먼저 사진을 받아오기 위한 부분이다.

 

https://developer.mozilla.org/ko/docs/Web/API/FileReader

 

FileReader - Web API | MDN

FileReader 객체는 웹 애플리케이션이 비동기적으로 데이터를 읽기 위하여 읽을 파일을 가리키는File 혹은 Blob 객체를 이용해 파일의 내용을(혹은 raw data버퍼로) 읽고 사용자의 컴퓨터에 저장하는

developer.mozilla.org

FileReader를 통해서 input에 있는 이미지를 'data:머시기~~' 이렇게 url로 변환하려고 했다.

 

다른 image 태그에서 src로 해당 url을 받아와서 미리보기를 만들기 위함이었다.

 

그리고 이미지와 텍스트들이 담겨져 있는 object를 같이 post를 해서 DB에 등록하려고 했다.

const registerMenu = () => {

	const data = new FormData();
    
	const menuData = {
			// 메뉴 데이터
	};
	const json = JSON.stringify(menuData);
	const blob = new Blob([json], {
		type: "application/json",
	});

	data.append("createMenuDto", blob);
	data.append("file", menuImage);
    
	axios({
		method: "post",
		url: "https://ecomap.kr/api/v1/menus",
		headers: {
			"Content-Type": "multipart/form-data",
		},
		data: data,
	}).then((Response) => {
		if (Response.status === 200) {
			console.log("메뉴 등록 되었습니다.");
		} else {
			alert("등록 오류가 생겼습니다. 다시 시도해주세요.");
		}
	});
};

메뉴를 등록하는 과정이다. 

 

사진과 글을 동시에 post하고 싶을 때는 Content-Type을 'multipart/form-data'로 선언해야 한다.

 

그리고 여기서 필요한게 FormData 라는 자료형이다. 

https://developer.mozilla.org/en-US/docs/Web/API/FormData

 

FormData - Web APIs | MDN

The FormData interface provides a way to easily construct a set of key/value pairs representing form fields and their values, which can then be easily sent using the fetch() or XMLHttpRequest.send() method. It uses the same format a form would use if the e

developer.mozilla.org

그냥 파일들과 텍스트들을 담을 수 있는 그릇을 만들어주는 것이다.

 

왜냐하면 텍스트는 application/json으로 보내줘야하기 때문에 그릇을 먼저 불러와주고

그 안에 알맹이들을 내가 원하는대로 수정해서 그릇에 담아주는 것이다. 

 

Blob을 활용하여 type을 application/json으로 바꿔주고 data에 넣어주고 File에는 맨 위 코드에서 불러온 menuImage를 넣어주었다.

 

그래서 딱 post를 하는 순간

 

500 에러 바로 떴다.

 

백엔드 개발자 분한테 여쭤보니 아예 File 자체가 null로 오고 있다는 것이었다.

 

음 뭐지...?

 

변환해준 url 그냥 열어도 이미지 잘 나오는데 왜 api가 그걸 못 받지...?

 

FormData의 키 값 오타도 확인해보고

menuImage가 잘 바뀌고 있는지도 콘솔에 찍어보고

FormData 안에 데이터가 잘 담겨있는지도 확인해봐도

 

너무 멀쩡하다....

 

그냥 통신 자체가 아예 안 되는 것이었다.

 

application/json 형식만 보고 이미지 파일이 계속 안 오는 것이었다.

 

 

오늘 장장 2시간 동안 백엔드 개발자 분이랑 끙끙대다가 해결했다. 

 

 

axios 코드가 잘못된 것 같지 않아서 다시 이미지 파일의 본질로 돌아가보았다.

 

굳이 url로 변환 안하고 그냥 input으로 받은 file 그대로 넣어줘볼까? 생각해서 

<input
	className='hidden text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 cursor-pointer dark:text-gray-400 focus:outline-none dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400'
	id='file_input'
	type='file'
	onChange={(event) => {
		// let reader = new FileReader();
		if (event.target.files[0]) {
			setMenuImage(event.target.files[0]);
			// setMenuSelectedImage(event.target.files[0]);
			// reader.readAsDataURL(event.target.files[0]);
		}
		// reader.onloadend = () => {
		// 	const resultImage = reader.result;
		// 	setMenuImage(resultImage);
		// };
	}}
/>

다 주석처리하고 menuImage에 그냥 바로 파일 넣어줬다.

 

그랬더니...되네...?


reader.readAsDataURL();
 

이걸 하게 되면 이미지 data를 base64 형태로 바꾸게 된다.

 

base64는 사진 파일을 암호화? 인코딩? 을 한 결과이다. 

 

근데 우리가 사용하고 있는 api가 https라 암호화되어있는 파일을 또 읽으려고 하니 아예 인식 자체를 못한 것이었다.

 

네트워크 관련돼서 이렇게 또 하나 배우고 갑니다....

 
728x90