에러 핸들링과 로딩 상태 — 실패를 우아하게 다루기

Week 5 마무리: 네트워크는 언젠가 반드시 실패합니다

10초 핵심 요약

01

fetch가 "실패"로 안 잡는 경우

흔히 하는 오해가 하나 있습니다. 서버가 "그런 페이지 없음"(404)이나 "서버 오류"(500)를 응답해도, fetch는 이걸 네트워크 요청 자체는 성공한 것으로 봅니다. catch는 오직 요청 자체가 아예 도달하지 못했을 때(인터넷 끊김 등)만 실행됩니다. 그래서 응답은 왔지만 내용이 오류인 경우는 직접 확인해야 합니다. 구체적으로 어떤 오류였는지는 res.status로 상태 코드를 확인하면 됩니다(200, 404, 500 등).

const res = await fetch('/api/posts');
if (!res.ok) { // res.ok는 상태코드가 200번대일 때만 true
  throw new Error(`서버 오류: ${res.status}`);
}
const data = await res.json();
02

4가지 상태로 확장하기

Day 30에서는 로딩/성공/실패 3상태를 다뤘습니다. 오늘은 실패했을 때 사용자가 재시도할 수 있는 상태를 추가합니다.

로딩중

요청을 보낸 직후. 스피너 표시

성공

카드 렌더링. 빈 배열이면 안내 문구

실패

오류 메시지 + 재시도 버튼 표시

재시도 중

재시도 버튼 클릭 → 다시 로딩중 상태로 되돌림

async function loadPosts() {
  showLoading();
  try {
    const res = await fetch('/api/posts');
    if (!res.ok) throw new Error(`${res.status}`);
    const data = await res.json();
    renderPosts(data);
  } catch (err) {
    showError('불러오지 못했습니다', loadPosts); // 재시도 함수 자신을 넘김
  }
}
showErrorloadPosts 함수 자체를 넘겨서, 재시도 버튼의 onclick에 그대로 연결하면 "실패한 그 요청을 다시" 정확히 재현할 수 있습니다.
03

사용자에게 보여줄 메시지 vs 개발자용 로그

실제 에러 메시지(TypeError: Failed to fetch 같은)를 사용자에게 그대로 보여주면 혼란스럽습니다. 화면에는 "일시적인 문제가 발생했습니다. 다시 시도해주세요" 같은 친절한 문구를 보여주고, 실제 원인은 console.error로 개발자만 보는 곳에 남깁니다.

안 될 때 확인하세요 재시도를 눌러도 계속 실패한다면, F12 → Network 탭에서 실제 응답 상태 코드를 확인하세요(Day 22에서 배운 도구입니다). 404면 주소 오타, 500번대면 서버(Function) 쪽 코드 오류일 가능성이 높습니다.
04

오늘의 실습 + AI 프롬프트

1Day 30의 렌더링 코드에 res.ok 체크를 추가해, 서버가 오류 상태코드를 줄 때도 catch 로직이 타도록 만듭니다.
2실패 화면에 "다시 시도" 버튼을 추가하고, 클릭하면 loadPosts가 다시 실행되도록 연결합니다.
AI에게 이렇게 지시해 보세요: "이 loadPosts 함수에 res.ok 체크를 추가하고, 실패 시 '불러오지 못했습니다' 메시지와 재시도 버튼을 보여줘. 재시도 버튼을 누르면 loadPosts를 다시 호출해줘."
05

Day 35 완료 체크리스트

fetch가 404/500도 "성공"으로 처리한다는 것과 res.ok의 역할을 설명할 수 있다.
로딩/성공/실패/재시도 4상태를 직접 구현했다.
사용자용 메시지와 개발자용 콘솔 로그를 구분해서 처리했다.
JSON부터 여기까지, 일주일 내내 새로운 개념이 쉬지 않고 이어졌습니다. 지금 전부 완벽히 설명하지 못해도 괜찮습니다 — 필요하면 여기서 하루 정도 Day 29~35를 다시 훑고 넘어가세요. 다음 주(Week 6)부터는 새 개념 부담이 훨씬 적습니다.
스스로 설명해보기 — fetch가 404/500 응답을 받아도 왜 catch로 안 잡히는지 설명할 수 있나요?

오늘의 용어

res.ok
응답 상태코드가 200번대(성공)인지 여부를 알려주는 값
res.status
응답의 실제 HTTP 상태 코드(200, 404, 500 등)
재시도(retry) 패턴
실패한 요청을 사용자가 다시 시도할 수 있게 하는 UI 패턴