Front_end

오류코드 정리

Ta_m 2026. 5. 13. 18:06

백엔드 & 프론트엔드 오류 코드 

프론트엔드 개발자라면 한 번쯤 마주치는 그 빨간 에러 메시지들. 오늘은 HTTP 상태 코드별로 왜 발생하는지, 어떻게 해결하는지 정리해본다.


들어가며

서버와 클라이언트가 통신하는 한, 에러는 피할 수 없다. 중요한 건 에러가 났을 때 누구의 문제인지 빠르게 판단하고, 어떻게 해결할지 아는 것이다.

이 글에서는 HTTP 상태 코드를 기준으로 백엔드 측 오류와 프론트엔드 측 오류를 나눠서 정리하고, 실제 코드 예시와 함께 해결 방법을 살펴본다.


1. 백엔드 측 오류 (4xx, 5xx)

🔸 400 Bad Request — 잘못된 요청

발생 원인

가장 흔한 케이스는 클라이언트가 보낸 데이터에 문제가 있을 때다.

  • 필수 파라미터 누락
  • 데이터 타입 불일치 (예: Number를 받아야 하는데 String이 옴)
  • JSON 형식 오류

해결 방법

  • 입력값 검증 미들웨어 도입 (express-validator, Joi, Zod 등)
  • DTO 단계에서 유효성 검사
  • 명확한 에러 메시지 반환 ("email 필드가 누락되었습니다")
// Node.js 예시
app.post('/users', (req, res) => {
  const { email, password } = req.body;
  if (!email || !password) {
    return res.status(400).json({ 
      message: '필수 입력값이 누락되었습니다.' 
    });
  }
});

🔸 401 Unauthorized — 인증 실패

발생 원인

  • JWT 토큰 만료
  • 토큰 누락
  • 잘못된 인증 정보

해결 방법

  • 인증 미들웨어로 토큰 검증
  • Refresh Token으로 자동 재발급
  • 클라이언트에서 401 수신 시 로그인 페이지로 리다이렉트

여기서 중요한 건, 401은 "당신이 누군지 모르겠다"는 의미라는 점이다. 로그인부터 다시 해야 한다는 신호.


🔸 403 Forbidden — 권한 없음

발생 원인

  • 인증은 됐지만 해당 리소스 접근 권한 부족
  • 일반 유저가 관리자 페이지 접근 시도

해결 방법

  • 역할 기반 접근 제어(RBAC) 구현
  • 권한 체크 미들웨어 작성
  • 보안상 민감한 경우 403 대신 404로 응답 (리소스 존재 자체를 숨김)

TIP — 401과 403은 자주 헷갈린다. 한 줄로 정리하면 "401은 너 누구야?", "403은 너인 건 알겠는데 들어오면 안 돼".


🔸 404 Not Found — 리소스 없음

발생 원인

  • 존재하지 않는 엔드포인트
  • DB에 없는 데이터 조회

해결 방법

  • 라우트 핸들러 마지막에 404 처리 추가
  • DB 조회 결과 null 체크
  • 일관된 404 응답 형식 유지
// 404 핸들러
app.use((req, res) => {
  res.status(404).json({ message: '요청한 리소스를 찾을 수 없습니다.' });
});

🔸 409 Conflict — 충돌

발생 원인

  • 이메일/아이디 중복 가입
  • 동시성 문제로 데이터 충돌

해결 방법

  • DB 유니크 제약조건 활용
  • 사전 중복 체크 로직 구현

🔸 500 Internal Server Error — 서버 내부 오류

발생 원인

  • NullPointerException, undefined 접근
  • DB 쿼리 오류, 커넥션 끊김
  • 코드 버그

해결 방법

  • 글로벌 예외 핸들러 구현
  • try-catch로 비동기 에러 처리
  • 로깅 시스템 도입 (Winston, Morgan)
  • 모니터링 도구 연동 (Sentry, Datadog)
// Express 글로벌 에러 핸들러
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).json({ 
    message: '서버 내부 오류가 발생했습니다.' 
  });
});

500이 떴다고 무작정 서버 탓 하면 안 된다. 비즈니스 로직 예외는 500이 아닌 400대로 응답해야 한다. 그래야 프론트가 적절히 대처할 수 있다.


🔸 503 Service Unavailable — 서비스 이용 불가

발생 원인

  • 서버 점검/재배포
  • 트래픽 과부하

해결 방법

  • Retry-After 헤더로 재시도 시점 안내
  • Auto Scaling 적용
  • 로드 밸런서로 부하 분산

2. 프론트엔드 측 오류

🔸 CORS 정책 위반

가장 악명 높은 에러. 거의 모든 프론트엔드 개발자가 한 번쯤 만난다.

발생 원인

다른 출처(origin)의 API 호출을 브라우저가 차단한다.

해결 방법 (백엔드에서 처리)

const cors = require('cors');
app.use(cors({ origin: 'http://localhost:3000' }));

CORS는 이 글에서 다 다루기엔 너무 커서 따로 정리할 예정이다.


🔸 TypeError / ReferenceError

발생 원인

  • undefined/null 값에 접근
  • 정의되지 않은 변수 사용

해결 방법

  • 옵셔널 체이닝(?.)과 nullish 병합(??) 활용
  • TypeScript 도입으로 타입 안전성 확보
  • 기본값 설정
// 안전한 접근
const userName = user?.profile?.name ?? '익명';

이 한 줄 차이로 앱이 죽고 안 죽고가 결정된다.


🔸 Promise / async-await 에러

발생 원인

  • API 호출 실패 시 처리 누락
  • Unhandled Promise Rejection

해결 방법

  • try-catch 블록 사용
  • 상태 코드별 분기 처리
async function fetchUser() {
  try {
    const res = await fetch('/api/users');
    if (!res.ok) {
      if (res.status === 401) {
        // 로그인 페이지로 이동
      } else if (res.status === 404) {
        // 없음 처리
      }
      throw new Error(`HTTP ${res.status}`);
    }
    return await res.json();
  } catch (error) {
    console.error('API 호출 실패:', error);
  }
}

🔸 React 렌더링 오류

해결 방법

  • Error Boundary 컴포넌트로 감싸기
  • 폴백 UI 제공
  • 컴포넌트 단위 에러 격리

화면 한 부분에서 에러가 나도 전체 앱이 죽지 않게 만드는 게 중요하다.


3. 공통 핵심 전략

에러 핸들링의 본질은 결국 "예측 가능하게 만들기" 다. 아래 6가지는 어느 프로젝트에서나 통하는 원칙이다.

전략 설명
글로벌 에러 핸들링 모든 에러를 한 곳에서 일관된 형식으로 처리
명확한 에러 메시지 어떤 필드, 어떤 이유로 실패했는지 정확히 안내
로깅 모든 에러는 로그로 기록 (디버깅 필수)
사용자 친화적 메시지 프론트에서는 기술 용어 대신 이해하기 쉽게 표시
재시도 로직 5xx 에러는 일정 시간 후 재시도 (Exponential Backoff)
모니터링 Sentry 등으로 실시간 에러 추적

4. 꼭 기억할 4가지

지금까지 내용을 한 줄씩 압축하면 이렇다.

1. 4xx는 클라이언트 책임, 5xx는 서버 책임

코드를 봐야 할 곳이 다르다. 4xx가 떴는데 백엔드 코드만 보면 답이 안 나온다.

2. 비즈니스 로직 예외는 5xx가 아닌 4xx로

"이미 가입된 이메일입니다"는 서버가 망가진 게 아니라 사용자가 잘못한 거다. 400대로 응답하자.

3. 확실하지 않으면 4xx로

5xx 남발하면 진짜 서버 문제가 발생했을 때 묻혀버린다. 모니터링이 망가지는 지름길.

4. 프론트와 백엔드는 에러 응답 포맷을 미리 합의해야 함

// 이런 식으로 통일해두면 프론트가 행복해진다
{
  "success": false,
  "code": "INVALID_EMAIL",
  "message": "이메일 형식이 올바르지 않습니다.",
  "field": "email"
}

마무리

에러 코드를 잘 다루는 개발자는 디버깅 시간이 절반으로 준다. 그리고 더 중요한 건, 사용자에게 친절한 앱을 만들 수 있다는 점이다.

다음 글에서는 가장 자주 만나는 그 녀석 — CORS 에 대해서만 깊게 파볼 예정이다.


해당 포스팅은 멋쟁이사자처럼 AI 세션 발표 자료를 기반으로 작성되었습니다.