繁体   English   中英

如何在 Nuxt.js 中捕获服务器错误,以免页面渲染崩溃? (Vue)

[英]How to catch server errors in Nuxt.js so it doesn't crash page render? (Vue)

语境

这个问题与我的另一个问题有关, How to handle apollo client errors crashing page render in Nuxt? ,但我会尽量保持隔离,因为我希望这个问题只关注 Nuxt(减去 apollo)。 但是,我决定单独提出这个问题,因为我正在寻找一个完全不同的响应/解决方案。

问题

我目前正在维护一个生产 Nuxt/Vue 应用程序,该应用程序使用@nuxt/apollo模块发出 GraphQL 请求。

问题在于,我们所依赖的 GraphQL 服务器不时出现故障并返回 HTML 错误页面,从而导致 Apollo 客户端崩溃。 但是因为我们将 Apollo 作为 nuxt 模块加载,它也会使页面渲染管道崩溃。 给我们一个看起来像这样的通用服务器错误页面;

页面错误

服务器错误 应用程序发生错误,无法提供您的页面。 如果您是应用程序所有者,请查看您的日志以获取详细信息。

以及以下堆栈跟踪:

 ERROR  Network error: Unexpected token < in JSON at position 0                                                            08:11:04

  at new ApolloError (node_modules/apollo-client/bundle.umd.js:92:26)
  at node_modules/apollo-client/bundle.umd.js:1588:34
  at node_modules/apollo-client/bundle.umd.js:2008:15
  at Set.forEach (<anonymous>)
  at node_modules/apollo-client/bundle.umd.js:2006:26
  at Map.forEach (<anonymous>)
  at QueryManager.broadcastQueries (node_modules/apollo-client/bundle.umd.js:2004:20)
  at node_modules/apollo-client/bundle.umd.js:1483:29
  at processTicksAndRejections (node:internal/process/task_queues:94:5)

但是,这些堆栈跟踪都不允许我们查看 nuxt 在哪里抛出错误,因此我们可以处理它。

我们尝试了什么

在过去的几周里,我们已经用尽了所有选项来调查这个问题。 我们首先尝试通过使用所有 3 个 apollo 库抽象的错误处理解决方案直接在 Apollo 级别处理错误来解决它:

  • @nuxt/apollo模块
  • vue-apollo
  • apollo-client

如果您想了解更多信息(即使它与这个问题无关),您可以在此处阅读有关我原来的问题的更多信息

但是,现在我想知道是否有办法通过以下方式处理这些页面呈现错误:

  • 使错误以静默方式失败,因此页面仍然正常呈现
  • 允许我们重定向到另一个页面。

由于我们目前使用的 apollo nuxt 模块不适用于此,我想知道 Nuxt 是否支持某种方式来处理错误。

Nuxt 的文档在错误处理方面非常有限,这并没有多大帮助。 充其量,它包含有关错误页面以及如何使用context.error重定向到错误页面的信息。 但它没有关于如何捕获常见错误的专门页面。 我有一种感觉 Nuxt 钩子可能是答案,但是关于它们的文档很难导航并且也很少。

我在 nuxt 错误处理上找到的最完整的信息源是这篇文章, NuxtJS 中的错误处理,其中没有任何建议对我们有用

概括

当我们使用的@nuxt/apollo nuxt 模块崩溃时,我们的 nuxt 应用程序崩溃了。 我们想知道是否有某种标准的 nuxt 方法来捕获它,或者唯一可能的解决方案是迁移我们的整个应用程序以不使用@nuxt/apollo模块并使用 ES6 promise 语法并手动加载apollo-client作为一个独立的库进入应用程序,没有深度集成到 nuxt 生命周期中。

编辑:我自己认为问题出在 Vue Apollo 插件或 Nuxt Apollo 模块的某个地方,以及那里的错误是如何处理的。 我认为您可以直接在 Apollo 模块上处理错误,但这在 SSR 中是不可能的。

您必须记住,您可能需要针对 CSR 和 SSR 的另一种解决方案。

简而言之,发生的情况是renderRoute失败,并且由于这个 SSR 最终出现在 Nuxt 的默认errorMiddleware中。

1:直接调用 Apollo 查询,这使您可以完全控制该页面的错误处理,并且适用于 CSR 和 SSR

export default {
  mounted() {
    if (!this.books.length) {
      // client side
      this.fetchBooks()
    }
  },

  serverPrefetch() {
    this.fetchBooks()
  },
  methods: {
    fetchBooks() {
      this.$apollo
        .query({
          query: gql`
            query books {
              books {
                title
                author
                test
              }
            }
          `,
        })
        .catch((e) => {
          console.log(e)
        })
        .then((data) => {
          /// set books
        })
    },
  },
}

2:添加一个errorMiddleware钩子并在那里处理错误。 这仅适用于 SSR。 重要的是要理解渲染失败,因此您必须重定向或渲染另一个页面。

//nuxt.config.js
 hooks: {
    render: {
      errorMiddleware(app) {
        app.use((error, req, res, next) => {
          res.writeHead(307, {
            Location: '/network-error',
          })
          res.end()
        })
      },
    },
  },

3:在Apollo的error方法中返回false,这只对CSR有效

export default {
  apollo: {
    books: {
      query() {
        return gql`
          query books {
            books {
              title
              author
              test
            }
          }
        `
      },
      error() {
        return false
      },
    },
  },
}

为了防止页面崩溃,您需要处理错误并隔离它们,以免它们影响其他组件的呈现。 这可以通过ErrorBoundary的错误处理概念来实现。 您可以创建一个通用组件来重用ErrorBoundary逻辑。 这种方法还有其他几个好处。

  • 有助于使组件免受错误处理逻辑的影响
  • 允许我们使用声明式组件组合,而不是依赖于命令式 try/catch
  • 我们可以随心所欲地使用它——包装单个组件或整个应用程序部分。

以下是如何创建错误边界的示例。

export default {
  name: 'ErrorBoundary',
  data: () => ({
    error: false
  }),
  errorCaptured (err, vm, info) {
    this.error = true
  },
  render (h) {
    return this.error ? h('p', 'Something went wrong') : this.$slots.default[0]
  }
}

现在,您可以将任何组件包装到错误边界并隔离给定的错误,

<error-boundary>
  <counter />
</error-boundary>

ErrorBoundary组件的注意事项

使用errorCaptured钩子时有一些注意事项。 目前,仅在以下位置捕获错误:

  • 渲染函数
  • 观察者回调
  • 生命周期钩子
  • 组件事件处理程序

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM