백엔드 & 프론트엔드 오류 코드
프론트엔드 개발자라면 한 번쯤 마주치는 그 빨간 에러 메시지들. 오늘은 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 세션 발표 자료를 기반으로 작성되었습니다.
'Front_end' 카테고리의 다른 글
| TypeScript (0) | 2026.05.06 |
|---|---|
| 강의 자료 2 (0) | 2026.02.25 |
| 리엑트 server.js 예외처리방법 (0) | 2026.01.01 |
| React 개발자를 위한 가장 쉬운 Node.js 백엔드 연동 가이드 (0) | 2025.11.03 |
| ☁️구름톤 자바스크립트 기초 정리 (0) | 2025.05.03 |