Flutter中GraphQL订阅连接异常问题求助
问题概述
使用graphql: ^5.1.3包开发Flutter应用时,查询和Mutation功能正常,但订阅功能无法工作。日志显示WebSocket连接建立后立即断开,订阅返回错误事件。
客户端代码
@Singleton() class GraphQlClient { GraphQLClient? client; void init() { _initConnection(); } void _initConnection() async { final graphQlHost = UrlTool.graphQlUrl(); final subscriptionQlHost = UrlTool.subscriptionUrl(); final token = getIt<LoginCubit>().state.userToken; logger.i('init basic connection'); logger.i(token); final httpLink = HttpLink(graphQlHost); final AuthLink authLink = AuthLink( getToken: () async { final sharedPref = await SharedPreferences.getInstance(); final token = sharedPref.getString(kMerchantToken); return token == null ? null : 'Bearer $token'; }, ); // 安全获取token final link = Link.split( (request) => request.isSubscription, WebSocketLink( subscriptionQlHost, config: SocketClientConfig( initialPayload: {'Authorization': 'Bearer $token'}, // 为WebSocketLink添加token ), ), authLink.concat(httpLink), ); client = GraphQLClient( link: link, cache: GraphQLCache(), defaultPolicies: DefaultPolicies( watchMutation: Policies(fetch: FetchPolicy.networkOnly), watchQuery: Policies(fetch: FetchPolicy.networkOnly), query: Policies(fetch: FetchPolicy.networkOnly), mutate: Policies(fetch: FetchPolicy.networkOnly), subscribe: Policies(fetch: FetchPolicy.networkOnly), ), ); } }
订阅监听代码
getIt<GraphQlClient>() .client ?.subscribe$OrderUpdated( Options$Subscription$OrderUpdated( fetchPolicy: FetchPolicy.networkOnly, variables: Variables$Subscription$OrderUpdated(id: getIt<TabletChooserCubit>().state.selectedTablet?.id ?? ''), ), ) .listen(_updateOrders);
日志信息
I/flutter (12107): Connected to websocket. I/flutter (12107): Initialising connection I/flutter (12107): Disconnected from websocket.
订阅错误事件

排查方向与解决方案
WebSocket Token一致性问题:
当前WebSocketLink的initialPayload使用的是LoginCubit同步获取的token,而AuthLink是异步从SharedPreferences取的token,两者可能存在不一致(比如LoginCubit的token未更新)。建议WebSocketLink也改用异步方式获取最新token:WebSocketLink( subscriptionQlHost, config: SocketClientConfig( initialPayload: () async { final sharedPref = await SharedPreferences.getInstance(); final token = sharedPref.getString(kMerchantToken); return {'Authorization': token == null ? '' : 'Bearer $token'}; }, ), ),WebSocket URL协议正确性:
确认subscriptionQlHost使用的是WebSocket协议(ws://或wss://),而非HTTP协议(http://或https://),协议不匹配会导致连接立即断开。客户端初始化时机问题:
_initConnection是异步函数,但init()未等待其完成就可能执行订阅,导致client未初始化完全。修改init()为异步函数:Future<void> init() async { await _initConnection(); }调用时先等待初始化完成再执行订阅:
await getIt<GraphQlClient>().init(); // 后续执行订阅逻辑后端订阅参数与配置问题:
错误截图显示Cannot read properties of undefined (reading '0'),大概率是后端处理订阅请求时解析参数出错。检查传入的id是否为空字符串(selectedTablet?.id为空时会传空值),后端是否接受空id;同时确认后端已正确配置WebSocket支持,允许客户端Origin访问,且OrderUpdated订阅字段存在并配置正确。
内容的提问来源于stack exchange,提问作者Marko Karajlovic

