实验性WebSockets
历史上,WebSockets一直是Apollo Kotlin中最复杂且易出错的部分之一,原因如下:Apollo Kotlin因为:
- WebSocket传输协议没有官方规范,不同的实施方式有不同的行为。
- WebSockets是有状态的,使用旧版Kotlin原生内存模型使它们工作具有挑战性。
- 由于WebSockets是长连接,它们更容易出错,知道何时(或是否)重试是难题。
- 并非所有订阅都在WebSockets上发生。一些使用HTTP multipart进行示例。
从4.0.0版本开始,Apollo Kotlin提供了一个新的com.apollographql.apollo.network.websocket
包包含新的 WebSocketNetworkTransport
和 WebSocketEngine
的实现(替代当前实现中的 com.apollographql.apollo.network.ws
)。
该 com.apollographql.apollo.network.websocket
实现提供以下功能:
- 默认使用 graphql-ws 协议,它已成为事实上的标准。使用其他协议仍然是可能的,但有一个主要且指定的协议可以确保我们能编写出一个良好且稳健的测试方案。
- 没有继承旧内存模型设计,使得代码大大简化。特别是,
WebSocketEngine
现在是事件驱动的,并且没有进行流量控制的尝试。如果您的缓冲区增长过多,您的 订阅 会失败。 - 与 ApolloClient 的
retryOnError
API 兼容。 - 更一致地处理不同的 订阅 传输方式。
状态
虽然它们包含在 @ApolloExperimental
中,但我们相信新的 .websocket
API 比非实验性的 .ws
API 更稳健。它们在非库用例中是安全的。
“实验性”标签是为了考虑到基于社区反馈所需的 API 破坏性更改。理想情况下,不需要进行任何更改。
在反馈阶段之后,当前的 .ws
API 将被弃用,而 .websocket
API 将通过移除 @ApolloExperimental
注释来被提升为稳定版本。
迁移指南
在简单的情况下,如果您没有配置底层的 WsProtocol
或重试逻辑,迁移应围绕将 com.apollographql.apollo.network.ws
更换成 com.apollographql.apollo.network.websocket
所在位置进行:
// Replaceimport com.apollographql.apollo.network.ws.WebSocketNetworkTransportimport com.apollographql.apollo.network.ws.WebSocketEngine// etc...// Withimport com.apollographql.apollo.network.websocket.WebSocketNetworkTransportimport com.apollographql.apollo.network.websocket.WebSocketEngine// etc...
由于我们目前还不能移除当前的 API,ApolloClient.Builder
的快捷 API 仍然指向 .ws
实现。要使用较新的 .websocket
实现,直接传递一个 websocket.WebSocketNetworkTransport
:
// Replaceval apolloClient = ApolloClient.Builder().serverUrl(serverUrl).webSocketServerUrl(webSocketServerUrl).webSocketEngine(myWebSocketEngine).webSocketIdleTimeoutMillis(10_000).build()// Withimport com.apollographql.apollo.network.websocket.*// [...]ApolloClient.Builder().serverUrl(serverUrl).subscriptionNetworkTransport(WebSocketNetworkTransport.Builder().serverUrl(webSocketServerUrl)// If you didn't set a WsProtocol before, make sure to include this.wsProtocol(SubscriptionWsProtocol())// If you were already using GraphQLWsProtocol, this is now the default//.wsProtocol(GraphQLWsProtocol()).webSocketEngine(myWebSocketEngine).idleTimeoutMillis(10_000).build()).build()
为了考虑到非WebSocket传输,例如多部分订阅,重试现在在 ApolloClient
而不是 NetworkTransport
处进行处理。
// Replaceval apolloClient = ApolloClient.Builder().subscriptionNetworkTransport(WebSocketNetworkTransport.Builder().serverUrl(url).reopenWhen { _, _ ->delay(1000)true}.build())// Withval apolloClient = ApolloClient.Builder().subscriptionNetworkTransport(WebSocketNetworkTransport.Builder().serverUrl(url).build())// Only retry subscriptions.retryOnError { it.operation is Subscription }
以上使用的是默认重试算法
- 如果配置了 网络监视器,请等待网络可用。
- 否则使用指数退避。
要更详细地自定义重试逻辑,请参阅 网络监视页面。