error-handling - 如何在我的 Vue Graphql 组件中使用错误并让其他错误在全局范围内处理?
问题描述
我们将 Vue 与 apollo 一起使用,我很难正确处理错误。
这是我们的组件
<template>
<div v-if="product">
<router-view :key="product.id" :product="product" />
</div>
<div v-else-if="!this.$apollo.loading">
<p>Product is not available anymore</p>
</div>
</template>
<script>
import productQuery from "@/graphql/product.graphql";
export default {
name: "ProductWrapper",
props: ["productId"],
apollo: {
product: {
query: productQuery,
variables() {
return {
productId: this.productId,
};
},
},
},
};
</script>
如果产品不再可用,我们在后端有三个选项:a)后端可以发送null
而不会出错 b)使用联合发送一个错误对象作为数据的一部分
c)使用 apollo 发送一些错误扩展,以便于错误处理在客户端
选项 a) 似乎是一个奇怪的选项 选项 b) 对于我们的用例来说太复杂了。所以我决定选择c):
在我们的后端,我们使用 apollo 错误扩展来发送一些适当的错误代码供客户端处理。
{
data: { }
errors: [
{
"message": "NOT_FOUND",
"locations": ...,
"path": ...
"extensions": {
"details": [],
"errorCode": "NOT_FOUND",
"message": "NOT_FOUND",
"classification": "DataFetchingException"
}
]
}
一切正常,因为产品结果为 null ,因为没有发送数据,只是一个错误。但是 vue-apollo 正在将它记录到 console.error 中。我不希望任何日志记录到 console.error 因为用户在他的浏览器中看到一个红色标记。但是如果没有其他人处理过这个错误,我希望它在 console.error 中弹出。
我可以在三个地方添加错误处理:
- 查询定义中的 error()
- $error() 所有查询的默认处理程序
- 错误链接
ErrorLink 似乎是错误的地方,因为只有组件中的查询知道 NOT_FOUND 不是致命的,但有时会发生。$error 也是如此
那我怎么说:这个错误可能会发生,我对此做好了充分的准备。所有其他错误应由 ErrorLink 处理。如何使用组件中的错误?
解决方案
我对 vue-apollo 错误处理的概述。
SmartQuery 错误处理程序
文档:https ://apollo.vuejs.org/api/smart-query.html
error(error, vm, key, type, options) 是出现错误时调用的钩子。error 是具有 graphQLErrors 属性或 networkError 属性的 Apollo 错误对象。vm 是相关的组件实例。key 是智能查询键。类型是“查询”或“订阅”。options 是最终的 watchQuery 选项对象。
未记录:如果您返回false
错误处理将停止并且不调用默认错误处理程序(Apollo 提供程序)。如果您返回true
或不返回任何内容(又名undefined
),则会调用默认错误处理程序。
代码示例
export default {
name: "ProductWrapper",
props: ['productId'],
apollo: {
product: {
query: productQuery,
variables() {
return {
productId: this.productId
}
},
error(errors) {
console.log("Smart Query Error Handler")
console.log(errors.graphQLErrors)
return false;
}
}
}
}
VueApolloProvider 错误处理程序
文档: https ://apollo.vuejs.org/api/apollo-provider.html
所有智能查询和订阅的全局错误处理程序
重要提示:这不适用于突变。
未记录:当智能查询的错误处理程序返回时,不会调用它false
代码示例
const apolloProvider = new VueApollo({
defaultClient: apolloClient,
errorHandler: (errors) => {
console.log("Provider errorHandler")
console.log(errors)
}
});
VueApolloProvider $error 特殊选项(没用)
文档 https://apollo.vuejs.org/guide/apollo/special-options.html
$error 在默认处理程序中捕获错误(请参阅错误高级选项 > 智能查询)
代码示例(错误)
const apolloProvider = new VueApollo({
defaultClient: apolloClient,
defaultOptions: {
error(errors) {
console.log("Provider $error")
console.log(errors)
}
}
});
这是我的第一次尝试,但它会在安装组件时调用并为我们提供完整的组件。见https://github.com/vuejs/vue-apollo/issues/126
代码示例(可以吗?)
const apolloProvider = new VueApollo({
defaultClient: apolloClient,
defaultOptions: {
$error() {
return (errors) => {
console.log("Provider $error handler")
console.log(errors.graphQLErrors)
}
},
},
});
这样就调用了 $error 函数。但它就像默认的 errorHandler 一样被调用(见上文)。文档似乎是错误的。所以这个方法对我来说似乎没什么用。正如您在此调试屏幕截图中所见,它的使用方式与其他错误处理程序一样:
错误链接
代码示例
import {onError} from "apollo-link-error";
const errorHandler = onError(({ networkError, graphQLErrors }) => {
console.log("Link onError")
console.log({ graphQLErrors, networkError})
})
const link = split(
// split based on operation type
({query}) => {
const definition = getMainDefinition(query);
return definition.kind === 'OperationDefinition' &&
definition.operation === 'subscription'
},
wsErrorHandler.concat(wsLink),
errorHandler.concat(httpLink)
);
重要:这是在任何其他 ErrorHandler 之前调用的,它适用于查询、订阅和突变
突变捕获
文档 https://apollo.vuejs.org/guide/apollo/mutations.html
代码示例 1
async submit() {
await this.$apollo.mutate({
mutation: productDeleteMutation,
variables: {
productId: this.product.id
},
}).catch((errors) => {
console.log("mutation .catch error")
console.log(errors)
})
}
代码示例 2 您也可以使用 try/catch:
async submit() {
try {
await this.$apollo.mutate({
mutation: productDeleteMutation,
variables: {
productId: this.product.id
},
})
} catch (errors) {
console.log("mutation try/catch error")
console.log(errors)
}
}
唯一可以调用的其他处理程序是 onError ErrorLink(见上文),它将在 catch 错误处理之前调用。
vue 使用 errorCaptured 处理突变
将此生命周期钩子添加到您的组件中以捕获来自突变的错误。
errorCaptured(err, vm, info) {
console.log("errorCaptured")
console.log(err.graphQLErrors)
return false
}
文档:https ://vuejs.org/v2/api/#errorCaptured
更多链接:https ://medium.com/js-dojo/error-exception-handling-in-vue-js-application-6c26eeb6b3e4
它仅适用于突变,因为智能查询的错误由 apollo 本身处理。
vue 全局 errorHandler 的突变错误
您可以拥有一个 vue 默认错误处理程序来从突变中捕获 graphql 错误
import Vue from 'vue';
Vue.config.errorHandler = (err, vm, info) => {
if (err.graphQLErrors) {
console.log("vue errorHandler")
console.log(err.graphQLErrors)
}
};
它仅适用于突变,因为智能查询的错误由 apollo 本身处理。
文档 https://vuejs.org/v2/api/#errorHandler
window.onerror
vue 之外的错误可以用纯 javascript 处理
window.onerror = function(message, source, lineno, colno, error) {
if (error.graphQLErrors) {
console.log("window.onerror")
console.log(error.graphQLErrors)
}
};
这不适用于 vue 组件内部或外部的突变、查询或订阅,因为它们由 vue 或 apollo 本身处理(如果未处理,则打印到 console.err)
文档 https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onerror
概括
同时捕获突变和查询错误的唯一方法是使用 ApolloLink 的 onError。服务器、网络和身份验证错误应该在那里被捕获,因为这些不是特定于任何操作的。
补充说明
探讨如何处理后端的错误
https://blog.logrocket.com/handling-graphql-errors-like-a-champ-with-unions-and-interfaces/
推荐阅读
- ios - Flutter 应用程序在更新 Flutter 后无法启动
- php - if then 嵌套语句导致页面无法加载
- javascript - 这个javascript语法是否正确?Node,js 抛出语法错误
- char - 如何在 C++ 中将 double 变量转换为 char 数组?
- core-data - 修改 CoreData 时如何在 SwiftUI 中更新 TabView?
- django - 没有名为“mysite.settings”的模块
- flutter - 图片未上传 Flutter
- mysql - 将多列合并为一个新列,同时保留原始列
- arrays - 检查数组是否下降到局部最小值,然后在 C 中上升
- r - 我可以省略 r 中数据集的搜索结果吗?