使用Ferry包时Flutter GraphQL Subscription无法生效如何解决?
核心问题
你遇到的卡在connection_init阶段的核心原因是 Ferry WebSocketLink使用的GraphQL订阅协议和Apollo Server端的协议不匹配:
- Apollo Server v3及更高版本默认使用
graphql-ws实现的新版订阅协议(对应Ferry中的GraphQLProtocol.graphqlTransportWs) - Ferry WebSocketLink如果不显式指定协议,部分版本会默认使用旧版
subscriptions-transport-ws协议,导致服务端无法识别客户端发送的connection_init握手消息,不会返回connection_ack响应,整个订阅流程就会卡在握手阶段。
修复代码
你只需要在初始化WebSocketLink时显式指定和服务端匹配的协议即可:
var link = WebSocketLink( "ws://localhost:4000/graphql", initialPayload: {"subscriptionParam": arg}, // 匹配Apollo Server默认的新版订阅协议 protocol: GraphQLProtocol.graphqlTransportWs, ); var client = Client(link: link); client.request(request).listen((data) { log(data.toString()); }, onError: (error, stack) { log("Subscription error: " + error.toString()); });
如果你使用的是Apollo Server v2或更早版本,服务端用的是旧版subscriptions-transport-ws协议,就把上面的协议参数换成GraphQLProtocol.subscriptionsTransportWs。
额外注意事项
- 如果你需要在同一个Ferry Client中同时使用queries/mutations和subscriptions,不要直接把Client的链路设置为WebSocketLink,要使用
SplitLink按操作类型分流:订阅请求走WebSocket链路,普通查询/变更走HTTP链路,示例如下:
final httpLink = HttpLink('http://localhost:4000/graphql'); final wsLink = WebSocketLink( "ws://localhost:4000/graphql", initialPayload: {"subscriptionParam": arg}, protocol: GraphQLProtocol.graphqlTransportWs, ); final splitLink = Link.split( (request) => request.isSubscription, wsLink, httpLink, ); final client = Client(link: splitLink);
- 如果你在Apollo Server端配置了订阅连接的
onConnect校验钩子,需要确认你传递的initialPayload字段格式符合服务端的校验要求,否则也会导致握手被服务端拒绝。
内容的提问来源于stack exchange,提问作者Aramis Romero
相关产品推荐
相关产品推荐

