【问题标题】:How Do I consume errors in my Vue Graphql component and let other errors be handled globally?如何在我的 Vue Graphql 组件中使用错误并让其他错误在全局范围内处理?
【发布时间】:2021-06-21 06:32:17
【问题描述】:

我们将 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)send an error object as part of the data with unions 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 中弹出。

我可以在三个地方添加错误处理:

  1. 查询定义中的error()
  2. $error() 所有查询的默认处理程序
  3. ErrorLink

ErrorLink 似乎是错误的地方,因为只有组件中的查询知道 NOT_FOUND 不是致命的,但有时会发生。 $error 也是如此

那我怎么说:这个错误可能会发生,我已经为此做好了充分的准备。所有其他错误应由 ErrorLink 处理。如何使用组件中的错误?

【问题讨论】:

    标签: error-handling graphql apollo vue-apollo


    【解决方案1】:

    我对 vue-apollo 错误处理的概述。

    SmartQuery 错误处理程序

    文档https://apollo.vuejs.org/api/smart-query.html

    error(error, vm, key, type, options) 是一个钩子,当有 错误。 error 是带有 graphQLErrors 的 Apollo 错误对象 属性或 networkError 属性。 vm 是相关组件 实例。 key 是智能查询键。类型是“查询”或 '订阅'。 options 是最终的 watchQuery 选项对象。

    未记录:如果您返回 false,则错误处理将停止,并且不会调用默认错误处理程序(Apollo Provider)。如果您返回 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 一样被调用(见上文)。文档似乎是错误的。所以这个方法对我来说似乎没什么用。正如您在此调试屏幕截图中所见,它的使用方式与其他错误处理程序一样:

    错误链接

    文档: https://www.apollographql.com/docs/react/data/error-handling/#advanced-error-handling-with-apollo-link

    代码示例

    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(见上文),它将在捕获错误处理之前调用。

    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/

    【讨论】:

      猜你喜欢
      • 2018-08-07
      • 2021-01-26
      • 2019-02-03
      • 1970-01-01
      • 2019-07-31
      • 1970-01-01
      • 1970-01-01
      • 2016-06-16
      • 1970-01-01
      相关资源
      最近更新 更多