[React] HTTP 오류 처리하기

summereuna🐥·2023년 5월 20일
0

React JS

목록 보기
55/69

오류 처리하기


HTTP 요청을 전송하는 경우에도 잘못된 것이 있다면 오류가 발생할 수 있다.

  • 네트워크 연결이 없어서 생기는 오류
  • 네트워크 연결이 있고 요청은 전송되었지만 오류 응닫ㅂ 코드를 넘겨 받는 기술적인 오류

404, 500, 401 같은 HTTP Status 오류가 발생할 수 있다.
이런 경우에는 많은 정보를 제공하지 않으므로 구글링해서 응답코드를 알아보면 된다..^^!

  1. 정보 응답(100 – 199)
  2. 성공적인 응답(200 – 299)
  3. 리디렉션 메시지(300 – 399)
  4. 클라이언트 오류 응답(400 – 499)
  5. 서버 오류 응답(500 – 599)
  • 서버가 401, 403 같은 응답을 하면, 서버는 요청을 받았지만, 내가 원하는 응답을 주지 않았음을 의미한다.
    즉, 기술적으로는 성공적으로 응답을 받았지만 응답에 오류 상태 코드가 포함되어 있어서 오류 문자를 받는 것이다.
  • 500대 응답은 서버에 오류가 발생했을 때 받게된다.

이것이 웹의 방식이다.

유효하지 않은 URL로 요청을 보내보자.

//유효하지 않은 URL로 요청보내기
const response = await fetch("https://swapi.dev/api/film/");

REST 엔드포인트지만 REST API가 지원하지 않는 부분이다.
요청을 발신하면 로딩상태에서 멈춰있다. 요청을 발신했지만 데이터는 돌아오지 않는다.
이는 사용자에게 좋은 경험이 아니다. 따라서 이 앱을 사용하는 사용자에게 오류 메시지 같은 것을 표시하여 문제가 발생했음을 알리는 것이 좋다.


404 상태코드가 떴다. 이 경우에는 서버가 준비하지 못한 리소스를 요청했다는 의미이다.

이런 오류를 처리하려면 상태관리가 필요하다.

error state로 상태관리를 해보자.

1. 초기에는 오류가 없기 때문에 초기 값으로 null로 설정한다.

const [error, setError] = useState(null);

2. 버튼이 클릭되면 먼저, 이전에 받았을 수도 있는 에러를 초기화한다.

const fetchMoviesHandler = async () => {
    setIsLoading(true);
    //이전에 받았을 수도 있는 에러 초기화
    setError(null);
    //...
  };

3.

  • then()을 사용하면 catch()를 추가하여 오류를 확인하면 된다.
  • async await구문을 사용하면 try-catch 구문으로 오류를 확인하면 된다.
    코드를 시도(try)하여 잠재적인 오류를 포착(catch)하는 것이다.
const fetchMoviesHandler = async () => {
    setIsLoading(true);
    //이전에 받았을 수도 있는 에러 초기화
    setError(null);
 
  //시도할 코드
    try {
      const response = await fetch("https://swapi.dev/api/film/");
      const data = await response.json();
      const transformedMovies = data.results.map((movieData) => {
        return {
          id: movieData.episode_id,
          title: movieData.title,
          openingText: movieData.opening_crawl,
          releaseDate: movieData.release_date,
        };
      });
      setMovies(transformedMovies);

      setIsLoading(false);
      
    //발생할수 있는 잠재적인 오류 포착
    } catch (error) {
      setError("Error");
    }
  };

그런데 문제는 fetch API는 이러한 에러 상태 코드를 실제 에러로 취급하지는 않는다.
실제로 오류 상태 코드를 받아도 기술적인 오류로 처리하지 않는다.
가져오지 못한 데이터로 어떤 작업을 하려고 할때만 오류가 발생한다.

이는 우리가 원하는 처리 방식이 아니다. 따라서 오류 상태 코드를 받았을 때 실제 오류가 발생하게 하는 것이 좋은 처리 방식이다.

  • axios 같은 경우에는 요청 전송에 성공한다면 오류 상태 코드에 맞는 오류를 만들어 전달한다.
  • fetch API는 그렇지 않으므로 직접 구현해보자 ^^!

페치후 받게되는 response 객체에는 ok라는 필드가 있다.
이는 요청이 성공적인지 아닌지 표시하는 부분이다.
따라서 응답이 OK인지 아닌지 확인하여 자체적으로 오류를 만들어 표시해 보자.
여기에 적당한 오류 메시지를 만들어 새로운 오류를 만들면 된다.

function App() {
  const [movies, setMovies] = useState([]);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState(null);

  const fetchMoviesHandler = async () => {
    setIsLoading(true);
    //이전에 받았을 수도 있는 에러 초기화
    setError(null);

    try {
      const response = await fetch("https://swapi.dev/api/films/");

      //데이터 파싱 전에 response 체크 하여 오류 메시지 만들기
      if (!response.ok) {
        throw new Error("Something went wrong!");
      }

      const data = await response.json();

      const transformedMovies = data.results.map((movieData) => {
        return {
          id: movieData.episode_id,
          title: movieData.title,
          openingText: movieData.opening_crawl,
          releaseDate: movieData.release_date,
        };
      });
      setMovies(transformedMovies);
    } catch (error) {
      setError(error.message);
    }

    //데이터 다 받아오면 로딩 끝내기 / 에러 발생하면 로딩이 필요 없기 때문에 로딩 중단하기
    setIsLoading(false);
  };

  return (
    <React.Fragment>
      <section>
        <button onClick={fetchMoviesHandler}>Fetch Movies</button>
      </section>
      <section>
        {!isLoading && movies.length > 0 && <MoviesList movies={movies} />}
        {!isLoading && movies.length === 0 && !error && <p>Found no movies.</p>}
        {isLoading && <p>Loading...</p>}
        {!isLoading && error && <p>{error}</p>}
      </section>
    </React.Fragment>
  );
}

export default App;

이렇게 여러가지 시나리오를 다룰 줄 알아야 한다.

JSX 코드 안에서 모든 조건을 확인하는 대신 다른 방법을 사용할 수도 있다.

//...
  //이렇게 변수 만들어 내용을 출력할 수 있다.
  let content = <p>Found no movies.</p>;

  if (movies.length > 0) {
    content = <MoviesList movies={movies} />;
  }
  if (error) {
    content = <p>{error}</p>;
  }
  if (isLoading) {
    content = <p>Loading...</p>;
  }

  return (
    <React.Fragment>
      <section>
        <button onClick={fetchMoviesHandler}>Fetch Movies</button>
      </section>
      <section>{content}</section>
    </React.Fragment>
  );
}

export default App;
profile
Always have hope🍀 & constant passion🔥

0개의 댓글