Flutter客户端连接.NET Core 3.1 SignalR Hub调用方法时出现‘Invocation canceled due to the underlying connection being closed’错误求助
我明白你现在遇到的这个问题有多头疼——刚启动SignalR连接就调用invoke却提示“Invocation canceled due to the underlying connection being closed”,换了IIS服务器也没解决。咱们一步步来排查和修复这个问题:
1. 先捕获连接错误并确认连接状态
你的Flutter代码里,start()之后直接调用invoke,但没有检查连接是否真的成功建立,也没捕获start过程中的错误。先修改代码,添加错误捕获和状态校验:
Future<void> signalr() async { const serverUrl = "<serverurl>"; final hubConnection = HubConnectionBuilder().withUrl(serverUrl).build(); // 先设置onclose回调,打印具体错误信息 hubConnection.onclose(({error}) { print('Connection closed: ${error?.toString() ?? "No error message"}'); }); try { await hubConnection.start(); print('Connection state: ${hubConnection.state}'); // 确认连接处于活跃状态再调用方法 if (hubConnection.state == HubConnectionState.connected) { final result = await hubConnection.invoke("joinRoom", args: ['1']); print('Result: $result'); hubConnection.on('RecieveMessage', (message) { print('sasta123'+ message.toString()); }); } else { print('Failed to connect, current state: ${hubConnection.state}'); } } catch (e) { print('Error starting connection: $e'); } }
2. 调整CORS配置以适配SignalR需求
虽然你已经添加了CORS,但SignalR需要额外的配置支持(比如允许凭据)。修改Startup.cs中的CORS规则:
app.UseCors(x => x .AllowAnyMethod() .AllowAnyHeader() .SetIsOriginAllowed(origin => true) // 生产环境请替换为具体允许的域名 .AllowCredentials()); // 关键:SignalR WebSocket和长轮询可能需要这个
3. 明确指定传输方式并检查IIS支持
SignalR默认会尝试最优传输方式,但有时候Flutter端和服务端的协商会出问题。可以在Flutter端明确指定传输方式,同时确保IIS启用了WebSockets功能:
Flutter端指定传输
final hubConnection = HubConnectionBuilder() .withUrl(serverUrl, HttpConnectionOptions( transports: {HttpTransports.websockets, HttpTransports.longPolling}, )) .build();
IIS启用WebSockets
- 打开服务器管理器 → 添加角色和功能 → 找到Web服务器(IIS) → 应用程序开发 → 勾选WebSocket协议,完成安装后重启IIS。
4. 调整超时和心跳参数
你已经设置了服务端的KeepAliveInterval和客户端的serverTimeoutInMilliseconds,但客户端的心跳间隔应该比服务端的短,确保连接不会被判定为超时:
hubConnection.serverTimeoutInMilliseconds = 300000; // 5分钟,和服务端KeepAliveInterval一致或更长 hubConnection.keepAliveIntervalInMilliseconds = 25000; // 25秒,定期发送心跳包
5. 检查服务端日志获取详细错误
你已经开启了EnableDetailedErrors = true,现在去查看服务端的日志(比如IIS的日志、应用程序日志),找到连接关闭时的具体错误信息——这往往是定位问题的关键,比如认证失败、路由错误等。
6. 确认Hub方法名称和参数匹配
确保服务端的ChatHub里存在joinRoom方法,且参数类型和客户端传递的一致(客户端传的是['1'],即字符串类型的参数,服务端方法应该接受string roomId这类参数)。
按照上面的步骤一步步排查,应该能找到问题所在。如果还是不行,把Flutter端打印的错误信息和服务端日志贴出来,能帮你进一步定位。
内容的提问来源于stack exchange,提问作者Abdul Mateen

