회원가입을 구현하기 위해 이미지 파일을 백엔드로 전송해야했다
이미지를 업로드하고 업로드 성공 시 미리보기 위한 컴포넌트
const ProfileImage = ({ onFileChange }) => {
const [selectedImage, setSelectedImage] = useState(null);
const handleImageChange = (event) => {
const file = event.target.files[0];
if (file) {
const reader = new FileReader();
reader.onloadend = () => {
setSelectedImage(reader.result);
onFileChange(file); // 부모 컴포넌트로 파일 전달
};
}
};
return(
<Label form="file">
{selectedImage ? (
<Image src={selectedImage} alt="선택한 이미지" />
) : (
<>
<DefaultImage src={ProfileBasic} alt="기본이미지" />
</>
)}
<StyledInput id="file" type="file" accept="image/*" onChange={handleImageChange} />
</Label>
)
}
//styled-components 생략
FileReader 라는 객체를 이용해서 파일을 업로드 했다.
FileReader는 File, Blob 객체를 사용해 특정 파일을 읽어들여 자바스크립트에서 파일에 접근할 수 있도록 도와주는 도구이다.
onloadend 라는 이벤트 핸들러를 사용했는데, 파일의 읽기 작업이 성공/실패에 관계없이 완료되었을 때 발생한다.
( onloadend는 파일 읽기가 완료되었을 때 로딩 스피너를 감추는 등의 작업에 사용이 적절)
이번 상황에서는 onloadend 보다 onload 사용이 더 적절해 보인다
(onload는 읽기 작업이 성공적으로 완료되었을 때 발생)
이미지 업로드를 성공적으로 하고나면
상위 컴포넌트에서 백엔드로 이미지와 JSON 데이터 전송
실패했던 코드
const handleSubmitButton = (event) => {
event.preventDefault();
if (true) { //selectedFile
const formData = new FormData();
formData.append("image", selectedFile);
const request = {
email: "123456@gmail.com",
password: "1234",
};
formData.append("request", JSON.stringify(values));
axios
.post(`apiURL`,formData , {
headers: {
'Content-Type': "multipart/form-data",
},
})
.then(function (response) {
// 성공적으로 응답 받았을 때의 처리
console.log("응답 데이터:", response.data);
navigate("/JudgePage");
})
.catch(function (error) {
// 오류 발생 시의 처리
console.error("오류 발생:", error);
console.log(request);
let values = formData.keys();
for (const pair of values) {
console.log(pair,'폼데이터');
}
});
}
};
콘솔로 찍어봤을 때 데이터가 들어있긴 했는데
'Content-Type': "multipart/form-data" 도 지정해줬는데 이렇게 보내면 백엔드에서 아래 오류가 확인됐다
에러코드:
WARN 114209 — [nio-8080-exec7] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content-Type 'application/octet-stream' is not supported]
FormData는 파일과 텍스트 데이터를 함께 서버로 전송하기 위해서 사용됨
📌오류난 이유📌
FormData는 주로 텍스트 데이터를 다루는데 최적화 되어있기 때문에
단순 JSON 데이터를 FormData로 추가하고 서버로 보내는 경우
이를 일반 텍스트 데이터로 처리하게 되어 서버에서 해당 데이터가 JSON임을 인식하지 못함
FormData에 추가할 수 있는 데이터 유형은 String,File,Blob, FormData객체 자체,숫자, 불리언 등 기본데이터 라고 한다
해결방법
const json = JSON.stringify(values);
const blob = new Blob([json], { type: "application/json" });
formData.append("request", blob);
Blob 객체를 생성해 객체의 타입을 application/json으로 설정해 append 하면 된다
완성된 코드
const SignupInfo = (props) => {
//로그인 정보 관리
const [selectedFile, setSelectedFile] = useState(null);
const [values, setValues] = useState({
email: "",
password: "",
});
const handleFileChange = (file) => {
setSelectedFile(file);
};
const handleChange = (e) => {
setValues((prevValues) => ({
...prevValues
}));
};
const handleSubmitButton = (event) => {
//정보들을 서버로 전송
event.preventDefault();
if (selectedFile) {
const formData = new FormData();
formData.append("image", selectedFile);
const json = JSON.stringify(values);
const blob = new Blob([json], { type: "application/json" });
formData.append("request", blob);
axios
.post(`https://umcfriend.kro.kr/api/v1/users`, formData, {
headers: {
"Content-Type": "multipart/form-data",
},
})
.then(function (response) {
// 성공적으로 응답 받았을 때의 처리
})
.catch(function (error) {
// 오류 발생 시의 처리
console.error("오류 발생:", error);
});
}
};
return (
<>
<Title title="회원가입" />
<AppContainer>
<InfoMessage>먼저 프로필 사진을 등록해주세요 <p>*</p> </InfoMessage>
<LogoContainer>
<ProfileImage
onFileChange={handleFileChange}
selectedFile={selectedFile}
/>
</LogoContainer>
<InfoMessage>아이디와 비밀번호를 입력해주세요 <p>*</p></InfoMessage>
<LoginForm onSubmit={handleSubmit}>
<Input
type="text"
name="email"
value={values.email}
onChange={handleChange}
placeholder="이메일"
/>
<Input
type="password"
name="password"
value={values.password}
onChange={handleChange}
placeholder="패스워드"
autoComplete="new-password"
/>
<Input
type="password"
name="pwck"
value={values.passwordCheck}
onBlur={checkWrongPW}
placeholder="패스워드 확인"
autoComplete="new-password"
/>
참고