入门篇六 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>

三、捕获异步错误

页面中的异步操作可能会失败,比如接口请求。用 useAsyncDatauseFetch 时,错误会自动被 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路由自动生成:告别手动配置路由的日子


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

相关推荐
薛定猫AI2 小时前
【技术干货】用 design.md 驯服 AI 生成前端:从 Awesome Design 到工程化落地实践
前端·人工智能
kyriewen2 小时前
你的JS代码总在半夜崩溃?TypeScript来“上保险”了
前端·javascript·typescript
iReachers2 小时前
HTML打包EXE配置管理教程:多项目打包设置一键保存、加载与切换
java·前端·javascript
武藤一雄2 小时前
WPF中ViewModel之间的5种通讯方式
开发语言·前端·microsoft·c#·wpf
霍理迪2 小时前
Vue路由——route
前端
whuhewei3 小时前
js事件循环
前端·javascript
TheRouter3 小时前
构建一个支持多模型的 AI 聊天应用:React + TheRouter API 全栈教程
前端·人工智能·react.js
xiaofan11063 小时前
Pretext:无 DOM 的多行文本测量与排版库
前端·javascript
yuki_uix3 小时前
面试题里的 Custom Hook 思维:从三道题总结「异步状态管理」通用模式
前端·react.js·面试