HTTP 409 error Conflict: 단순한 해결 (문제 해결)

Devinix·2023년 11월 9일
0

[문제 해결]

목록 보기
7/29
post-thumbnail

개요

블로그 사이드 프로젝트를 진행하면서 회원가입 기능을 추가하고 있었다. 'useSignUpForm'이라는 커스텀 훅을 이용해 서버에 요청을 보내고 있었다.

코드를 살펴보도록 하자.


  const handleSignUp = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();

    const formData = new FormData();
    formData.append("id", inputValues.id);
    formData.append("password", inputValues.password);

    if (inputValues.password !== inputValues.confirmPassword) {
      alert("비밀번호가 일치하지 않습니다.");
      return;
    }

    if (window.confirm("회원가입 하시겠습니까?")) {
      alert("회원가입 되었습니다.");
    } else {
      alert("취소합니다.");
      return;
    }

    fetch(
        process.env.NEXT_PUBLIC_API_BASE_URL + "/user/join",
      {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: formData,
        cache: "force-cache",
      }
    )
      .then((response) => {
        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }
        return response.json();
      })
      .then((result) => console.log(result))
      .catch((error) => console.error("Error:", error));

    setInputValues({ id: "", password: "", confirmPassword: "" });
  };

코드 설명

폼 제출 이벤트를 방지:
e.preventDefault(); 호출을 통해 폼이 기본적으로 페이지를 새로 고침하지 않도록 한다.

FormData 객체를 생성:
사용자의 입력 값을 id와 password 필드에 담아 서버로 보낼 FormData 객체를 만든다.

비밀번호 확인:
사용자가 입력한 비밀번호(inputValues.password)와 비밀번호 확인(inputValues.confirmPassword)이 일치하는지 검사한다. 일치하지 않으면 경고창을 띄우고 함수를 종료한다.

회원가입 확인:
window.confirm을 사용해 사용자에게 회원가입을 할 것인지 재확인한다. '확인'을 누르면 회원가입이 완료되었다는 알림이 뜨고, '취소'를 누르면 취소 알림이 뜨며 함수가 종료된다.

서버로의 HTTP POST 요청:
fetch API를 사용하여 "multipart/form-data" 타입의 POST 요청을 해당 API 엔드포인트로 보낸다. 이 때 캐시 모드를 "force-cache"(getStaticProps, 기존 Next.Js의 SSG와 유사)로 설정한다.

응답 처리:
서버로부터의 응답이 성공적이지 않으면(즉, response.ok가 false이면) 에러를 던진다. 그렇지 않다면 응답을 JSON 형태로 변환하여 콘솔에 출력한다.

에러 처리:
요청이 실패하거나 다른 에러가 발생하면 콘솔에 에러 메시지를 출력한다.

입력 값 초기화:
setInputValues 함수를 호출하여 id, password, confirmPassword 필드를 빈 문자열로 초기화한다.

문제 상황

Next.Js 애플리케이션에서 회원가입 폼의 데이터를 서버로 전송하는 과정에서 HTTP 409 Conflict 오류가 발생했다. 이 오류는 클라이언트에서 서버로 POST 요청을 보낼 때 발생했다.

원인

분석 결과, 클라이언트는 Content-Type을 application/json으로 설정했으나, 실제로 서버에 전송된 데이터는 FormData 객체였다. 이러한 Content-Type과 본문 데이터 타입의 불일치가 오류의 원인으로 밝혀졌다.

  const handleSignUp = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    
    // 이 부분
    const formData = new FormData();

    formData.append("id", inputValues.id);
    formData.append("password", inputValues.password);

    if (inputValues.password !== inputValues.confirmPassword) {
      alert("비밀번호가 일치하지 않습니다.");
      return;
    }

    if (window.confirm("회원가입 하시겠습니까?")) {
      alert("회원가입 되었습니다.");
    } else {
      alert("취소합니다.");
      return;
    }

    fetch(
        process.env.NEXT_PUBLIC_API_BASE_URL + "/user/join",
      {
        method: "POST",
        headers: {
           // 이 부분
          "Content-Type": "application/json",
        },
        body: formData,
        cache: "force-cache",
      }
    )
      .then((response) => {
        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }
        return response.json();
      })
      .then((result) => console.log(result))
      .catch((error) => console.error("Error:", error));

    setInputValues({ id: "", password: "", confirmPassword: "" });
  };

해결 과정

문제를 해결하기 위해 클라이언트의 요청 코드를 수정했다. FormData 객체 대신에 JSON 문자열을 생성하여 fetch 요청의 본문으로 사용했다. 이렇게 변경함으로써 Content-Type 헤더와 요청 본문의 형식이 일치하게 되었고, 서버는 요청을 성공적으로 처리할 수 있었다.

fetch(
    process.env.NEXT_PUBLIC_API_BASE_URL + "/user/join", 
  {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    loginId: inputValues.loginId,
    password: inputValues.password
  }),
  cache: "force-cache",
})

FormData 객체를 사용하는 부분을 제거하고, 대신 JSON 문자열을 직접 body에 전달함으로써 문제를 해결했다.

결론

클라이언트-서버 통신에서 Content-Type 헤더와 본문 데이터의 형식을 일치시키는 것의 중요성을 강조한다. 올바른 데이터 형식의 사용은 서버가 요청을 적절하게 처리하고 오류 없이 응답을 반환할 수 있도록 하는 핵심 요소이다. 개발자는 이와 같은 오류를 피하기 위해 항상 요청 헤더와 본문 데이터 타입이 일치하는지 확인해야 한다는 것을 다시 한 번 깨달을 수 있었다.

profile
프론트엔드 개발

0개의 댓글