入门篇六 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路由自动生成:告别手动配置路由的日子


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

相关推荐
M ? A13 小时前
Vue 的 scoped 样式穿透 React 不支持?用 VuReact 编译就行
前端·javascript·vue.js·react.js·面试·开源·vureact
zs宝来了13 小时前
Vue 3 Composition API:响应式系统与依赖追踪
前端·javascript·框架
李伟_Li慢慢13 小时前
wolfram详解山峦算法
前端·算法
村上小树13 小时前
非常简单地学习一下slate.js的原理
前端·javascript
web打印社区13 小时前
[特殊字符] 开源好物:web-print-pdf,让 Web 打印像调用接口一样简单!
前端·javascript·vue.js·electron
嗷o嗷o13 小时前
Android BLE 收到字节流以后,为什么业务状态还是不对
前端
莪_幻尘13 小时前
Prompt 工程化落地:从"手工咒语"到工业级软件系统
前端
荒天帝13 小时前
Android App 最强APM来袭
前端
vim怎么退出13 小时前
我给 Claude Code 写了一个自适应学习 Skill,7 天刷完浏览器原理
前端·人工智能
逍遥归来13 小时前
UICollectionViewDiffableDataSource 刷新方案总结
前端