Nuxt3服务端渲染时调用的接口报500时如何显示error.vue

跟着官网走

首先看官网案例

xml 复制代码
<script setup lang="ts">
  const route = useRoute()
  const { data, error } = await useFetch(`/api/movies/${route.params.slug}`)
  if (!data.value) {
    throw createError({ statusCode: 404, statusMessage: 'Page Not Found' })
  }
</script>

思路就是将setup中的代码通过await同步执行,请求完接口后对dataerror进行判断,然后就能按条件显示error.vue页面。其中,官方也更推荐用showError代替throw createError。但是这样的写的问题是:1、没有对接口调用进行封装;2、对接口的错误处理也没有封装。

努力调试

通常,我希望通过api.getUserInfo(data)这样的方式调用接口,封装方法看我另一篇文章。封装后,对于SSR时接口调用失败的处理,应该统一封装在$fetchonResponseError中,如:

javascript 复制代码
function fetchWrapper(url, opts) {
  return $fetch(url, {
    ...opts,
    onResponseError({ request, options, response }) {
      if (import.meta.server) {
        showError({ statusCode: 404, statusMessage: 'Page Not Found' })
      }
    },
  }).catch(() => {});
}

但尝试后发现,showError没有生效。进一步测试未做$fetch封装的几种情况:

xml 复制代码
<script setup>
const { data } = await useAsyncData(async () => {
  // 能生效
  showError({ statusCode: 404, statusMessage: 'Page Not Found' })
  
  const res = await $fetch(url, {
    onRequestError({ request, options, error }) {
      if (import.meta.server) {
        // onRequestError中能生效
        showError({ statusCode: 404, statusMessage: 'Page Not Found' })
      }
    },
    onResponseError({ request, options, response }) {
      if (import.meta.server) {
        // onResponseError中不生效
        showError({ statusCode: 404, statusMessage: 'Page Not Found' })
      }
    },
  })

  // 不生效
  showError({ statusCode: 404, statusMessage: 'Page Not Found' })
})
</script>

所以,不是封装导致的问题。总结一下,应该是请求前能生效,请求后及其回调都不生效。

大胆实践

个人猜测,这可能是Nuxt的一个小bug。我实践了一个可行的解决办法,就是建一个全局状态serverRequestError,在接口回调中更新此状态,在组件的setup的末尾判断一下此状态是否有值,有的话showError

stores/serverRequestError.js的代码如下:

javascript 复制代码
export const useServerRequestError = defineStore('serverRequestError', () => {
  const code = ref(-1)
  const reason = ref('')

  function create({ url, statusCode, statusMessage }) {
    code.value = statusCode
    reason.value = `${url} ${statusCode} ${statusMessage}`
  }

  function clear() {
    code.value = -1
    reason.value = ''
  }

  return {
    reason,
    create,
    clear,
  }
})

// 创建error信息
export function createServerRequestError(opts) {
  useServerRequestError().create(opts)}

// 检查是否有error
export function checkServerRequestError() {
  if (import.meta.server) {
    const store = useServerRequestError()

    store.reason && showError({
      statusCode: store.code || 404,
      statusMessage: store.reason,
    })
  }
}

// 清除error
export function clearServerRequestError() {
  useServerRequestError().clear()}

onResponseError中调用createServerRequestError()

vbscript 复制代码
$fetch(url, {
  onResponseError({ request, options, response }) {
    const { status, statusText } = response;

    if (import.meta.server){
      useServerRequestError().create({ url: request, statusCode: status, statusMessage: statusText })    }
  }
})

在需要检查的业务代码的末尾调用checkServerRequestError()

xml 复制代码
<script setup>
const { data } = await useAsyncData(async () => {
  const res = await apis.get404()
  return res
})

checkServerRequestError()
</script>

error.vue也别忘了调用clearServerRequestError()清除error信息:

思考优化

感觉这个自定义的全局状态与Nuxt提供的useError有点像,可惜尝试了很多办法,还是不知道useError怎么用进去。

还可以优化的点,就是Nuxt提供一个在SSR时的setup执行的结尾可执行的钩子来执行checkServerRequestError(),遗憾的是我还没发现可用的钩子。

还可以考虑在layout组件判断状态、或封装状态组件的方式来触发showError,但是都还不够优雅,如果有更好的方案,请评论区留言哦~

相关推荐
妙码生花7 分钟前
从 PHP 到 AI + Golang,程序员自救转型手记(十九):点选验证码代码逐行目检
前端·后端·go
Awu12271 小时前
⚡从零开发 Agent CLI(五)实现一个可治理、可扩展的工具系统
前端·人工智能·claude
咪库咪库咪1 小时前
Vue3-生命周期
前端
莪_幻尘2 小时前
你的 AI Skill 越多越蠢?Token 上下文爆炸的求生指南
前端·ai编程
lichenyang4532 小时前
从 has.echo 到异步 API 注册表:一次 ASCF API 回调不触发的排查复盘
前端
林瞅瞅2 小时前
Nuxt3 项目部署 Nginx 防盗链后特定 JS 文件 403 问题修复方案
前端
kyriewen3 小时前
别再每次都 Google 了:我整理了前端日常最常踩的 10 个 Git 坑,附速查表
前端·javascript·git
一颗奇趣蛋3 小时前
Web 视频开发完全指南:从入门到精通
前端
非洲农业不发达3 小时前
windows终端体验大升级,让你拥有macos级别的美化
前端·后端
妙码生花3 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(十七):登录接口完善,登录页接口整合,解决跨域
前端·后端·ai编程