如何解决如何在 Nuxt.js 中捕获服务器错误,以免导致页面渲染崩溃? (Vue) ErrorBoundry 组件的注意事项
背景
这个问题与我的另一个问题 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
如果您想阅读更多相关内容(即使它与此问题无关),您可以阅读我最初的问题 here
但是,现在我更想知道是否有办法通过以下方式处理这些页面呈现错误:
- 使错误无声无息地失败,因此页面仍然正常呈现
- 允许我们重定向到另一个页面。
由于我们目前使用的 apollo nuxt 模块不能用于此,我想知道 Nuxt 是否支持某种方式来处理错误。
Nuxt 的文档在错误处理方面非常有限,这并没有多大帮助。充其量,它包含有关错误页面以及如何使用 context.error
重定向到错误页面的信息。但它没有关于如何捕获常见错误的专门页面。我有一种感觉 Nuxt hooks 可能是答案,但关于它们的文档很难导航并且也很稀疏。
我在 nuxt 错误处理方面找到的最完整的信息来源是这篇文章 Error handling in NuxtJS,其中没有任何建议对我们有用。
总结
当我们使用的 @nuxt/apollo
nuxt 模块崩溃时,我们的 nuxt 应用程序崩溃。我们想知道是否有某种标准的 nuxt 方法来捕获它,或者唯一可能的解决方案是将我们的整个应用程序迁移到不使用 @nuxt/apollo
模块并使用 ES6 承诺语法并加载 {{1 }} 作为一个独立的库手动进入应用程序,没有深度集成到 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
},}
,
为了防止页面崩溃,您需要处理错误并隔离它们,以免它们影响其他组件的渲染。这可以通过 ErrorBoundry
的错误处理概念来实现。您可以创建一个通用组件来重用 ErrorBoundry
逻辑。这种方法还有其他几个好处。
- 有助于使组件不受错误处理逻辑的影响
- 允许我们使用声明式组件组合,而不是依赖于命令式 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>
ErrorBoundry
组件的注意事项
使用 errorCaptured
钩子时有一些注意事项。目前,错误仅在以下位置捕获:
- 渲染函数
- 观察者回调
- 生命周期钩子
- 组件事件处理程序
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。