오류 처리(Error Handling)

오류 처리(Error Handling)

Nuxt는 풀스택 프레임워크라서, 어쩔 수 없이 발생하는 사용자 런타임 오류도 다양한 컨텍스트에서 생길 수 있어요. Vue 렌더링 라이프사이클(SSR·CSR) 오류, 서버·클라이언트 시작 오류, Nitro 서버 라이프사이클 오류, JS 청크 다운로드 오류가 그것이에요. 각 오류를 어떻게 잡고 다루는지 정리할게요.

출처: https://nuxt.com/docs/4.x/getting-started/error-handling

용어: SSR은 Server-Side Rendering, CSR은 Client-Side Rendering을 뜻해요.

Vue 오류

onErrorCaptured로 Vue 오류에 훅을 걸 수 있어요. 또한 Nuxt는 어떤 오류가 최상위까지 전파되면 호출되는 vue:error 훅을 제공해요. 에러 리포트 프레임워크를 쓰면 vueApp.config.errorHandler로 전역 핸들러를 제공할 수 있는데, 처리된 오류를 포함해 모든 Vue 오류를 받아요.

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.config.errorHandler = (error, instance, info) => {
    // 오류 처리, 예: 서비스에 리포트
  }
})

vue:error 훅은 onErrorCaptured 라이프사이클 훅에 기반해요.

시작 오류

Nuxt 앱 시작 중 오류가 있으면 app:error 훅을 호출해요. 여기에는 Nuxt 플러그인 실행, app:created·app:beforeMount 훅 처리, HTML 렌더링(SSR), 앱 마운트(클라이언트), app:mounted 훅 처리가 포함돼요.

Nitro 서버 오류

이 오류에 대한 서버 사이드 핸들러는 현재 정의할 수 없지만, 오류 페이지를 렌더링할 수는 있어요.

JS 청크 오류

네트워크 연결 실패나 새 배포(해시된 JS 청크 URL이 무효화될 때) 때문에 청크 로딩 오류를 만날 수 있어요. Nuxt는 라우트 내비게이션 중 청크 로딩 실패 시 하드 리로드를 수행하는 내장 지원을 제공해요. experimental.emitRouteChunkErrorfalse(훅 완전 비활성화)나 manual(직접 처리)로 바꿔 동작을 변경할 수 있어요.

오류 페이지

Nuxt가 치명적 오류(서버의 처리되지 않은 오류, 또는 클라이언트에서 fatal: true로 만든 오류)를 만나면 JSON 응답(Accept: application/json 헤더로 요청된 경우)을 렌더링하거나 전체 화면 오류 페이지를 트리거해요.

app.vue 옆에 ~/error.vue를 추가해서 기본 오류 페이지를 커스터마이즈할 수 있어요.

<script setup lang="ts">
import type { NuxtError } from '#app'
const props = defineProps({
  error: Object as () => NuxtError,
})
const handleError = () => clearError({ redirect: '/' })
</script>
<template>
  <div>
    <h2>{{ error?.status }}</h2>
    <button @click="handleError">Clear errors</button>
  </div>
</template>

커스텀 오류에는 페이지·컴포넌트 setup 함수에서 호출할 수 있는 onErrorCaptured 컴포저블이나, Nuxt 플러그인에서 구성할 수 있는 vue:error 런타임 훅을 쓰는 걸 강력히 권장해요.

오류 페이지를 제거할 준비가 되면 clearError 헬퍼를 호출하면 돼요. 이 함수는 안전한 페이지로 리다이렉트할 선택적 경로를 받아요. 오류 페이지 렌더링은 완전히 별도의 페이지 로드이므로 등록된 미들웨어가 다시 실행된다는 점도 기억하세요.

오류 유틸

useError

function useError(): Ref<Error | { url, status, statusText, message, description, data }>

현재 처리 중인 전역 Nuxt 오류를 반환해요.

createError

function createError(err: string | { cause, data, message, name, stack, status, statusText, fatal }): Error

추가 메타데이터가 있는 오류 객체를 만들어요. 문자열을 전달하면 message로 설정되고, 객체를 전달하면 오류 속성을 담아요. Vue·Server 양쪽에서 쓸 수 있고 throw하도록 설계됐어요.

  • 서버에서 createError로 만든 오류를 throw하면 전체 화면 오류 페이지가 트리거되고, clearError로 지울 수 있어요.
  • 클라이언트에서는 비치명적(non-fatal) 오류가 throw되어 직접 처리하지만, fatal: true로 설정하면 전체 화면 오류 페이지를 트리거해요.
const route = useRoute()
const { data } = await useFetch(`/api/movies/${route.params.slug}`)
if (!data.value) {
  throw createError({
    statusCode: 404,
    statusMessage: 'Page Not Found',
  })
}

statusText 속성은 짧고 HTTP를 따르는 상태 텍스트(예: "Not Found")용이에요. 자세한 설명·여러 줄·비 ASCII 콘텐츠는 항상 message 속성을 써야 해요.

showError

function showError(err: string | Error | { status, statusText }): Error

클라이언트 어디서든, 또는 서버에서는 미들웨어·플러그인·setup() 함수 안에서 직접 호출할 수 있어요. 전체 화면 오류 페이지를 트리거하고 clearError로 지울 수 있어요. throw createError()를 쓰는 걸 권장해요.

clearError

function clearError(options?: { redirect?: string }): Promise<void>

현재 처리 중인 Nuxt 오류를 지워요. 안전한 페이지로 리다이렉트할 선택적 경로도 받아요.

컴포넌트에서 오류 렌더링

Nuxt는 <NuxtErrorBoundary> 컴포넌트도 제공해서, 사이트 전체를 오류 페이지로 바꾸지 않고 앱 안에서 클라이언트 사이드 오류를 처리하게 해줘요. 이 컴포넌트는 기본 슬롯 안에서 발생하는 오류를 처리하고, 클라이언트에서 오류가 최상위로 전파되는 걸 막아 #error 슬롯을 대신 렌더링해요. 다른 라우트로 내비게이션하면 오류는 자동으로 지워져요.

더 알아보기