에러 처리
14.3.1. HTTP 상태코드별 처리
- API 응답 에러는 HTTP 상태코드를 기준으로 분류하여 처리합니다.
- 각 상태코드에 대한 처리 전략을 사전에 정의하고, 일관되게 적용해야 합니다.
| 상태코드 | 의미 | 처리 전략 |
|---|---|---|
| 400 | 잘못된 요청 | 서버 응답의 유효성 검증 메시지를 사용자에게 표시합니다 |
| 401 | 인증 실패 | 토큰 갱신을 시도합니다. 갱신 실패 시 로그인 페이지로 리다이렉트합니다 |
| 403 | 권한 없음 | 접근 권한 부족 안내 메시지를 표시합니다 |
| 404 | 리소스 없음 | 요청한 데이터를 찾을 수 없음을 안내합니다 |
| 409 | 충돌 | 데이터 충돌 상황을 안내하고, 새로고침을 유도합니다 |
| 422 | 처리 불가 | 서버 유효성 검증 실패 메시지를 폼 필드에 매핑합니다 |
| 500 | 서버 오류 | 일반적인 서버 오류 메시지를 표시합니다. 상세 내용은 노출하지 않습니다 |
| 502/503 | 서비스 불가 | 서비스 점검 또는 일시적 오류 안내를 표시합니다 |
14.3.2. 네트워크 에러
- 서버 응답이 없는 경우(
error.response가undefined)는 네트워크 에러로 분류합니다. - 네트워크 에러와 타임아웃 에러는 구분하여 처리합니다.
typescript
// src/api/utils/error.ts
import type { AxiosError } from 'axios'
export function isNetworkError(error: AxiosError): boolean {
return !error.response && error.code !== 'ECONNABORTED'
}
export function isTimeoutError(error: AxiosError): boolean {
return error.code === 'ECONNABORTED'
}- 오프라인 상태 감지는
navigator.onLine속성과online/offline이벤트 리스너를 활용합니다. - Composable 함수(
useNetworkStatus)로 구현하여 컴포넌트에서 반응형으로 사용합니다.
14.3.3. 사용자 피드백
- API 에러 발생 시 사용자에게 적절한 피드백을 제공해야 합니다.
- 에러 메시지는 표준화된 형식으로 관리합니다.
typescript
// src/api/utils/notify.ts
const ERROR_MESSAGES: Record<string, string> = {
NETWORK_ERROR: '네트워크 연결을 확인해 주십시오.',
TIMEOUT_ERROR: '요청 시간이 초과되었습니다. 다시 시도해 주십시오.',
UNAUTHORIZED: '인증이 만료되었습니다. 다시 로그인해 주십시오.',
FORBIDDEN: '접근 권한이 없습니다.',
NOT_FOUND: '요청하신 데이터를 찾을 수 없습니다.',
SERVER_ERROR: '서버 오류가 발생했습니다. 잠시 후 다시 시도해 주십시오.',
DEFAULT: '오류가 발생했습니다.',
}
export function getErrorMessage(code: string): string {
return ERROR_MESSAGES[code] ?? ERROR_MESSAGES.DEFAULT
}- 서버에서 전달하는 에러 메시지가 있는 경우, 해당 메시지를 우선 사용합니다.
- 서버 메시지가 없거나 기술적 내용인 경우, 표준 메시지로 대체합니다.
14.3.4. 글로벌 에러 핸들러
- Axios 에러를 애플리케이션 표준 에러 객체로 변환하는 핸들러를 구현합니다.
AppError클래스를 정의하여 에러 타입을 통일합니다.
typescript
// src/api/errors/AppError.ts
export class AppError extends Error {
readonly status: number
readonly code: string
constructor(status: number, code: string, message: string) {
super(message)
this.name = 'AppError'
this.status = status
this.code = code
}
}typescript
// src/api/errors/handleApiError.ts
import type { AxiosError } from 'axios'
import { AppError } from './AppError'
import { isNetworkError, isTimeoutError } from '@/api/utils/error'
export function handleApiError(error: AxiosError): AppError {
if (isTimeoutError(error)) {
return new AppError(0, 'TIMEOUT_ERROR', '요청 시간 초과')
}
if (isNetworkError(error)) {
return new AppError(0, 'NETWORK_ERROR', '네트워크 오류')
}
const status = error.response?.status ?? 0
const data = error.response?.data as Record<string, string> | undefined
return new AppError(status, data?.code ?? 'UNKNOWN_ERROR', data?.message ?? '알 수 없는 오류')
}- 개별 API 호출에서
handleApiError를 사용하여 에러를 변환합니다. - 공통 처리가 필요한 경우 응답 인터셉터에서 변환을 수행합니다.