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

How to get the uri in callback of onError from apollo-link-error?

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

函数({操作、响应、graphQLErrors、网络错误、转发})

似乎无法从这些参数中获取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 }))

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

客户端仅包含一个 terminating link -- 通常是 HttpLinkBatchHttpLink。唯一的例外是当我们使用 split 函数来支持 WebSocketLink 和另一个终止 link 时。综上所述,您的客户通常只有一个 HttpLink 并且 link 将有一个 URL 用于发出请求——即您通常只有一个请求 URL 每个客户。除非您使用的是自定义 link 或其他非典型设置,否则在给定特定客户端的情况下,您应该已经可以在 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 将第二个 link 作为可选的第三个参数。因此,使用两个参数,您可以指定条件和满足条件时使用的 link。使用三个参数,您可以指定一个条件,一个 link 如果满足条件则使用 如果条件不满足则使用 link 。综上所述,如果您在上面的示例中只使用两个 URI,则可以只使用一个 split 而不是三个:

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

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