如何从 apollo-link-error 获取 onError 回调中的 uri?

Posted

技术标签:

【中文标题】如何从 apollo-link-error 获取 onError 回调中的 uri?【英文标题】:How to get the uri in callback of onError from apollo-link-error? 【发布时间】:2019-12-05 08:05:44 【问题描述】:

我使用 apollo-link-error 来处理 graphql 错误。我需要知道onError回调中当前链接的uri。但是,回调的签名如下:

函数(操作、响应、graphQLErrors、networkError、forward)

似乎无法从这些参数中获取 uri。所以我错过了什么吗?还是我需要使用其他工具来达到这个目的? 事实上,我需要知道 uri 用于重试目的(重试请求另一台服务器)。

我如下配置客户端,

var uriList = [uri1, uri2]
const customFetch = (uri, options) => 
    const dynamicURI = getOneURIFromURIList()
    return fetch(dynamicURI, options);

const errorLink = onError(( networkError, operation, forward ) => 
    if (needRetry(networkError)) 
        // Here, if I know the URI of the terminating link, I can removed it
        // from the uriList, and customFetch will not choose it again.
        return forward(operation)
    
)
const link = errorLink.concat(createHttpLink( fetch: customFetch ))

【问题讨论】:

分享您的客户端配置,包括链接,将有助于为您的问题提供更具体的答案。没有任何示例代码,很难提供一个笼统的答案。 @DanielRearden 感谢您的热情回复。我重新编辑了这个问题。在重新编辑的过程中,我发现customFetch的uri参数可能是我想要的。当重试发生时,它是上一次调用getOneURIFromURIList 的URI吗?我还没试过。 很遗憾,经过测试,发现customFetch的uri参数没有变化,默认是/graphql 使用未经测试但可行的解决方法来编辑我的答案,以解决您正在尝试做的事情。 【参考方案1】:

请求 URL 不可用作 onError 回调的参数。

客户端只包含一个terminating link——通常是HttpLinkBatchHttpLink。唯一的例外是当我们使用split 函数同时支持WebSocketLink 和另一个终止链接时。也就是说,您的客户通常只有一个HttpLink,并且该链接将有一个用于发出请求的 URL——即,您通常每个客户只有一个请求 URL。除非您使用自定义链接或其他非典型设置,否则对于特定客户端,您应该已经可以在 onError 回调上下文之外访问此 URL。

编辑:

我会建议一种更传统的负载平衡方法,而不是尝试在客户端执行此操作(例如,使用实际的负载平衡器或使用 nginx 实现功能)。这样一来,您的客户端将只有一个 URL 可用于初始请求或重试,并决定将哪个服务器用于请求将由后端处理。

也就是说,您应该能够通过使用上下文和split 函数来实现您想要做的事情。像这样的东西应该可以工作:

import  setContext  from 'apollo-link-context'
import  createHttpLink  from 'apollo-link-http'
import  split, from  from 'apollo-link'

const contextLink = setContext(() => (
  // you could return something other than the URI here, like a number
  // we just need some value that's unique to each link
  targetURI: getOneURIFromURIList()
))

const optionalHttpLink1 = split(
  (operation) => operation.getContext().targetURI === URI_1,
  createHttpLink( uri: URI_1 )
)

const optionalHttpLink2 = split(
  (operation) => operation.getContext().targetURI === URI_2,
  createHttpLink( uri: URI_2 )
)

const optionalHttpLink3 = split(
  (operation) => operation.getContext().targetURI === URI_3,
  createHttpLink( uri: URI_3 )
)

const errorLink = onError(( operation ) => 
  // call operation.getContext().targetURI to determine the URI used
)

const link = from([
  contextLink,
  optionalHttpLink1,
  optionalHttpLink2,
  optionalHttpLink3,
  errorLink,
])

您还需要确保删除 customFetch 选项以使上述操作生效。

还要注意split 将第二个链接作为可选的第三个参数。因此,使用两个参数,您可以指定条件和满足条件时使用的链接。使用三个参数,您可以指定一个条件、一个在满足条件时使用的链接一个在不满足条件时使用的链接。综上所述,如果您在上面的示例中只使用两个 URI,则可以只使用一个 split 而不是三个:

const httpLink = split(
  (operation) => operation.getContext().targetURI === URI_1,
  createHttpLink( uri: URI_1 ),
  createHttpLink( uri: URI_2 )
)

如果您有 2 个以上的 URI,则每个 URI 都需要一个 split

【讨论】:

非常感谢,您的回答确实帮我解决了问题。按照您的指南,我将 targetURI 放入上下文中(在您的代码中使用类似 contextLink 的内容)。我仍然使用customFetch(在我的代码中显示),在其中我可以将失败的 targetURL 从上下文中取出,然后选择一个新的来重试请求。

以上是关于如何从 apollo-link-error 获取 onError 回调中的 uri?的主要内容,如果未能解决你的问题,请参考以下文章

Apollo 网络(错误请求)错误未在 apollo-link-error 中捕获

使用 Apollo 和 React 捕获身份验证失败后如何正确重定向

onError 导入未在 Apollo 中使用

Apollo GraphQL 本地和全局错误处理

如何从其他面板从 JTextField 获取输入

在客户端处理 apollo-server 错误