현재 사용하고 있는 기술 스택은 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에 그냥 바로 파일 넣어줬다.
그랬더니...되네...?
이걸 하게 되면 이미지 data를 base64 형태로 바꾸게 된다.
base64는 사진 파일을 암호화? 인코딩? 을 한 결과이다.
근데 우리가 사용하고 있는 api가 https라 암호화되어있는 파일을 또 읽으려고 하니 아예 인식 자체를 못한 것이었다.
네트워크 관련돼서 이렇게 또 하나 배우고 갑니다....
'웹 > React' 카테고리의 다른 글
React - 가로 스크롤바 간단하게 만들기 (feat. tailwindCSS) (0) | 2023.12.04 |
---|---|
React 드롭다운 blur 이벤트 click 이벤트 올바르게 처리하기 (0) | 2023.08.11 |
React 드롭다운 메뉴 혼자서 만들어보기 - 라이브러리 X (0) | 2023.08.07 |