如何在 apollo 客户端中检测订阅(websocket)的断开和重新连接

Posted

技术标签:

【中文标题】如何在 apollo 客户端中检测订阅(websocket)的断开和重新连接【英文标题】:How to detect disconnect and reconnect for subscription(websocket) in apollo client 【发布时间】:2021-08-25 05:20:45 【问题描述】:

我正在构建一个聊天服务,我想处理订阅(websocket)连接断开的情况。 Apollo 客户端配置如下。我删除了不必要的代码,如缓存、authLink 等。

我如何使用 react 来做到这一点,阿波罗客户端?如果它断开连接,我想将其显示到聊天页面,当用户重新连接时,我想获取所有错过的聊天消息。这就是为什么我需要知道断开连接、连接事件

以下是此应用中使用的相关包:

"@apollo/client": "^3.3.7",
"subscriptions-transport-ws": "^0.9.18",
"react": "^17.0.1"
const httpLink = new BatchHttpLink( uri: config.API_URL )
const wsLink = new WebSocketLink(
  uri: config.WS_URL,
  options: 
    reconnect: true,
    connectionParams:       
      authToken: accessToken,
    ,
  ,
)

const splitLink = split(
  ( query ) => 
    const definition = getMainDefinition(query) 
    return definition.kind === 'OperationDefinition' && definition.operation === 'subscription'
  ,
  wsLink,
  httpLink
)
const client = new ApolloClient(
  cache,
  link: from([new SentryLink(), authLink, errorLink, splitLink]),
)

【问题讨论】:

【参考方案1】:

看来您要用于定位 WS 连接/断开连接事件的选项是 connectionCallback(请参阅 WebSocketLink 选项的完整列表 here)。

查看 WebSocketLink 源的lines 620-635,您可以看到提供的connectionCallback 被调用为GQL_CONNECTION_ERRORGQL_CONNECTION_ACK 接收的消息类型。因此,您应该能够使用此回调来定位这两个事件。

我还没有使用 Apollo 的 WebSocketLink,所以我无法确认它是否可以完全按预期工作。此外,在重新连接时获取所有丢失的聊天消息的行为可能需要您自己构建,因为它似乎不是默认重新连接行为的一部分(将取决于服务器实现;请参阅Apollo Server docs)。相反,WebSocketLink 似乎会在默认情况下在重新连接时将所有未发送的消息转发到服务器。

【讨论】:

我尝试了connectionCallback,它在建立新连接时会运行,但在websocket断开连接时它不会运行。这绝对是一个改进,但理想情况下我也想知道它什么时候被中断,这样我就只能获取在那段时间发生的聊天消息【参考方案2】:

我终于找到了解决办法。原来你可以先声明一个SubscriptionClient,然后把它插入WebSocketLink,而不是直接用WebSocketLink声明。

使用 SubscriptionClient,您可以监听必要的事件,而使用 WebsocketLink 则不太可能(或非常有限)。

不幸的是,在 Apollo 文档中没有提到 SubscriptionClient 或处理连接问题的方法。

import  WebSocketLink  from '@apollo/client/link/ws'
import  SubscriptionClient  from 'subscriptions-transport-ws' // <- import this

const wsClient = new SubscriptionClient(config.WS_URL, 
  reconnect: true,
  connectionParams: 
    authToken: accessToken,
  ,
)

const wsLink = new WebSocketLink(wsClient)

通过这样做,现在您可以使用wsClient 监听连接事件

wsClient.onConnected(() => console.log("websocket connected!!"))
wsClient.onDisconnected(() => console.log("websocket disconnected!!"))
wsClient.onReconnected(() => console.log("websocket reconnected!!"))

您可以收听更多事件。但是这些事件足以实现获取错过的聊天消息。

使用这些事件,在初始连接后,您可以存储disconnectTimestamp on disconnect 事件。当您收到onReconnected 事件时,您可以简单地获取在disconnectTimestamp 之后创建的聊天消息

【讨论】:

以上是关于如何在 apollo 客户端中检测订阅(websocket)的断开和重新连接的主要内容,如果未能解决你的问题,请参考以下文章

如何在生产中使用 apollo 订阅

如何在客户端 NextJS 中使用 Apollo GraphQL 订阅?

如何在 jest / apollo 客户端中捕获被拒绝的 graphql 订阅?

如何在 React 中为上传和订阅设置 Apollo 客户端?

如何在 apollo 订阅服务器上获取客户端 IP 地址?

如何在 Apollo 中关闭 GraphQL 订阅的套接字连接