入门篇六 Nuxt4错误处理:给应用装个安全气囊

文章目录

写代码最怕什么?不是写不出来,而是写出来后用户一操作就崩了。页面白屏、接口报错、路由找不到......这些问题如果处理不好,用户体验会非常糟糕。今天我们来学习 Nuxt 的错误处理机制,给应用装上"安全气囊"。

一、全局错误页面

当用户访问不存在的页面时,需要展示一个友好的 404 页面。Nuxt 让这件事变得很简单。

创建 error.vue(注意:在项目根目录,不是 pages 目录):

vue 复制代码
<script setup lang="ts">
const props = defineProps<{
  error: {
    url: string
    statusCode: number
    statusMessage: string
    message: string
  }
}>()

const handleError = () => clearError({ redirect: '/' })
</script>

<template>
  <div class="error-page">
    <h1>{{ error.statusCode }}</h1>
    <p>{{ error.statusMessage || '出错了' }}</p>
    <button @click="handleError">返回首页</button>
  </div>
</template>

<style scoped>
.error-page {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  text-align: center;
}

h1 {
  font-size: 6rem;
  color: #00dc82;
  margin-bottom: 1rem;
}

p {
  font-size: 1.5rem;
  color: #666;
  margin-bottom: 2rem;
}

button {
  padding: 0.75rem 1.5rem;
  background: #00dc82;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 1rem;
}

button:hover {
  background: #00b36b;
}
</style>

现在访问一个不存在的路由,比如 /abcdefg,就会显示这个错误页面。

二、针对不同错误码显示不同内容

404、500、403......不同的错误应该有不同的提示。优化一下:

vue 复制代码
<script setup lang="ts">
const props = defineProps<{
  error: {
    statusCode: number
    message: string
  }
}>()

// 根据错误码返回提示信息
const errorInfo = computed(() => {
  const errors: Record<number, { title: string; desc: string }> = {
    404: { title: '页面走丢了', desc: '您访问的页面不存在' },
    403: { title: '禁止访问', desc: '您没有权限访问此页面' },
    500: { title: '服务器开小差了', desc: '请稍后再试' }
  }
  return errors[props.error.statusCode] || { 
    title: '出错了', 
    desc: props.error.message 
  }
})

const goHome = () => clearError({ redirect: '/' })
const goBack = () => clearError()
</script>

<template>
  <div class="error-page">
    <h1>{{ error.statusCode }}</h1>
    <h2>{{ errorInfo.title }}</h2>
    <p>{{ errorInfo.desc }}</p>
    <div class="actions">
      <button @click="goBack">返回上一页</button>
      <button class="primary" @click="goHome">返回首页</button>
    </div>
  </div>
</template>

三、捕获异步错误

页面中的异步操作可能会失败,比如接口请求。用 useAsyncData 或 useFetch 时,错误会自动被 Nuxt 捕获:

vue 复制代码
<script setup lang="ts">
const { data, error } = await useFetch('/api/articles')

// 如果请求失败,error 会有值
if (error.value) {
  // 这里可以处理错误,或者抛出让全局错误页面处理
  throw createError({
    statusCode: 500,
    message: '获取文章列表失败'
  })
}
</script>

<template>
  <div v-if="data">
    <h1>文章列表</h1>
    <ul>
      <li v-for="article in data" :key="article.id">
        {{ article.title }}
      </li>
    </ul>
  </div>
</template>

四、手动创建错误

有时候业务逻辑需要主动抛出错误:

vue 复制代码
<script setup lang="ts">
const route = useRoute()
const articleId = route.params.id

const { data: article } = await useFetch(`/api/articles/${articleId}`)

// 文章不存在,抛出 404
if (!article.value) {
  throw createError({
    statusCode: 404,
    statusMessage: '文章不存在',
    fatal: true  // 致命错误,直接显示错误页面
  })
}
</script>

createError 的参数:

  • statusCode: HTTP 状态码
  • statusMessage: 状态消息
  • message: 详细错误信息
  • fatal: 是否致命(致命错误会直接跳错误页面)

五、使用 onErrorCaptured 捕获组件错误

在组件中捕获子组件的错误:

vue 复制代码
<script setup lang="ts">
const hasError = ref(false)

onErrorCaptured((err) => {
  console.error('捕获到错误:', err)
  hasError.value = true
  return false  // 返回 false 阻止错误继续传播
})
</script>

<template>
  <div v-if="hasError" class="error-fallback">
    <p>组件加载失败</p>
    <button @click="hasError = false">重试</button>
  </div>
  <ChildComponent v-else />
</template>

六、全局错误处理

在插件中设置全局错误处理器:

创建 plugins/error-handler.ts:

ts 复制代码
export default defineNuxtPlugin((nuxtApp) => {
  // 捕获 Vue 错误
  nuxtApp.hook('vue:error', (error, instance, info) => {
    console.error('Vue Error:', error)
    // 可以上报到错误监控平台
    // reportError(error)
  })
  
  // 捕获服务端错误
  nuxtApp.hook('app:error', (error) => {
    console.error('App Error:', error)
  })
})

七、API 错误处理

如果你的 Nuxt 项目有 API 路由(server/api),也需要处理错误:

ts 复制代码
// server/api/articles/[id].ts
export default defineEventHandler(async (event) => {
  const id = getRouterParam(event, 'id')
  
  // 参数校验
  if (!id || !/^\d+$/.test(id)) {
    throw createError({
      statusCode: 400,
      statusMessage: 'Invalid article ID'
    })
  }
  
  const article = await getArticleById(Number(id))
  
  // 资源不存在
  if (!article) {
    throw createError({
      statusCode: 404,
      statusMessage: 'Article not found'
    })
  }
  
  return article
})

八、开发环境显示详细错误

开发时需要看到详细的错误堆栈,但生产环境不应该暴露。Nuxt 默认就帮你处理好了:

  • 开发环境:显示完整错误信息和堆栈
  • 生产环境:只显示状态码和简单提示

你也可以在 nuxt.config.ts 中自定义:

ts 复制代码
export default defineNuxtConfig({
  // 开启 nitro 错误处理
  nitro: {
    errorHandler: '~/error-handler.ts'
  }
})

总结

错误处理是保证应用健壮性的关键:

场景 处理方式
页面不存在 error.vue
接口失败 useFetch 的 error 状态
业务错误 createError()
组件错误 onErrorCaptured
全局错误 插件中 hook

记住:永远不要让用户看到白屏或报错弹窗,给每个可能的错误都准备好兜底方案。

下一篇文章,我们聊聊数据获取,看看 Nuxt 怎么帮你优雅地请求接口。

相关阅读

入门篇三:Nuxt4组件自动导入:写代码少敲一半字

入门篇二:Nuxt 4路由自动生成:告别手动配置路由的日子


内容有帮助?点赞、在看、分享三连!评论区等你 💪

相关推荐
brien920 分钟前
为什么模型标称 1M,Google Antigravity 聊到 256K 却突然失忆?我们给它做了个原生行内监控圆环
前端
修炼的dance35 分钟前
录屏关键帧间隔多少合适?六档实测,2秒到10秒小了75.6%
前端
Lank_M41 分钟前
关键帧从1秒拉到10秒,录屏小87.3%,摄像头小10.8%
前端
补码缩写43 分钟前
用 ffprobe 拆录屏,八成字节在 29 个关键帧上
前端
百思不得小李1 小时前
一个复杂的动态表单是如何实现的
前端·设计模式
陈随易1 小时前
Cmder 停更 17 个月,2.0 支持 Windows Terminal
前端·后端·程序员
风骏时光牛马1 小时前
前沿视界
前端
kyriewen1 小时前
我扫了 814 个依赖,97 个还敢要 Node 10
前端·javascript·程序员
陈随易2 小时前
3000 万人在用的翻译插件,重写一遍就是一门生意
前端·后端·程序员
IT_陈寒2 小时前
Vue的这个响应式陷阱,差点让我加班到天亮
前端·人工智能·后端