Programming/Client

[Javascript] formData로 이미지, 문자열 묶어서 전달하기

Jiwoo 2023. 1. 8. 22:19

📌 상황

이름, 주소, 이미지 정보를 서버로 전달해야 했다.

이미지는 multer를 사용했기에 프론트에서 이미지 정보를 formData로 보내야 했고,

문자열로 데이터를 전달할 때와 axios의 header 안의 Content-Type이 달라졌다.

그렇기 때문에 이름, 주소는 문자열로 전달하고,

이미지를 formdata로 보내서 API를 두 번 호출해야했다.


그런데 나는 API 호출을 최소화하고 싶었기에 한 번에 같이 보낼 수 있는 방법이 없을까 고민했다.

아무리 검색해봐도 이렇게 정보를 함께 보내는 경우를 볼 수 없어서

백엔드 팀원과 새벽에 3시간을 고전하다가, 결국 해결책을 찾았다.

이름, 주소도 formdata 안에 넣어서 이미지와 함께 보내는 것이다.

이런 방법도 있다~ 하면서 참고로 봐주시면 좋겠다.

🤔 해결 과정

formData란?
HTML의 form을 대신하는 객체로, 직접 폼 객체를 만들어서 서버에 전달할 때 사용함.
주로 이미지를 전달할 때 사용함

1. 이미지 정보를 배열로 저장하기

// 이미지 파일 선택하면 실행되는 함수
// 이미지 정보가 담긴 배열이 상태에 저장됨
const onChangeImg = (e) => {
    e.preventDefault();

    if (e.target.files) {
        const imgArr = e.target.files;
        if (imgArr.length > 3) {
            alert('이미지는 3개까지 등록 가능합니다.');
            e.target.value = '';
        } else setImgs(imgArr); // 이미지 정보가 담긴 배
    }
};

2. 보낼 정보를 모두 formdata로 변환해서 전달하기

name, address, description 정보는 모두 상태값으로 만들어서
input을 통해 유저에게 값을 받았다고 가정했다.


이미지를 보내기 위해 formdata로 해당 배열을 감싸는 것처럼
위 정보들도 함께 감싸서 하나의 formdata를 만들었다.
그 다음에 API를 호출해서 formdata 자체를 전달하면 된다!

// 전송 누르면 실행되는 함수
const onClickRegistration = async () => {
    const formData = new FormData();

    // 모든 정보가 입력되야 실행됨
    if (name && address && description && owner && imgs) {
        formData.append('name', name);
        formData.append('address', `${address}${detailaddress}`);
        formData.append('description', description);
        Array.from(imgs).forEach((img) => {
            formData.append('file', img); // name명은 백과 맞춰야함
        });

        try {
            await axios(`/api/farms`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'multipart/form-data',
                    Authorization: `Bearer ${localStorage.getItem('token')}`,
                },
                data: formData,
            });
            alert('등록되었습니다.');
            navigate('/farm');
        } catch (e) {
            alert('등록에 실패했습니다.');
            console.log(e);
        }
    } else {
        alert('정보를 모두 입력해주세요.');
    }
};