如何在我的 Vue Graphql 组件中使用错误并让其他错误在全局范围内处理?

Posted

技术标签:

【中文标题】如何在我的 Vue Graphql 组件中使用错误并让其他错误在全局范围内处理?【英文标题】:How Do I consume errors in my Vue Graphql component and let other errors be handled globally? 【发布时间】: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 中弹出。

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

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

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

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

【问题讨论】:

【参考方案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/

【讨论】:

以上是关于如何在我的 Vue Graphql 组件中使用错误并让其他错误在全局范围内处理?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 WebStorm 在 Vue 组件或 .graphql 文件中的 apollo 对象内的 gql 查询中显示错误

如何在我的 .cshtml 页面中调用 Vue 组件?

如何将变量添加到 GraphQL 文件查询

如何在我的刀片文件中使用我的 vue 组件中的选择

从 vue-loader 缓存中删除已删除的组件

为多个 vue 属性重用 apollo graphql 查询定义