You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Dart中SignalR服务端协商超时TimeoutException问题求助

解决方案

1. 调整协商与请求超时时间

你的错误是协商阶段2秒超时,默认的HttpConnectionOptions.timeout为2秒,完全无法适配大量数据的协商与传输需求。需要手动设置更长的超时阈值:

final httpConnectionOptions = HttpConnectionOptions(
  accessTokenFactory: () => SharedPreferenceService().loginWithToken(),
  headers: defaultHeaders,
  logger: transportProtLogger,
  logMessageContent: true,
  timeout: const Duration(seconds: 30), // 延长协商超时时间
);

同时,调用invoke方法时单独设置请求超时,避免数据传输过程中超时:

await hubConnection.invoke(
  'GetAllBigStuff',
  timeout: const Duration(minutes: 5), // 根据实际数据量调整
).then((value) => fixation = value as List);

2. 修正KeepAlive配置时机

你当前在连接启动后设置keepAliveIntervalInMilliseconds,这不会生效——必须在hubConnection.start()之前完成配置:

final hubConnection = HubConnectionBuilder()
    .withUrl(
      'http://10.10/home',
      options: httpConnectionOptions,
    )
    .build();

// 移至start()之前配置
hubConnection.keepAliveIntervalInMilliseconds = 10 * 60 * 60 * 1000;
await hubConnection.start();

3. 强制使用WebSocket传输

默认情况下SignalR会自动协商传输方式,可能切换到长轮询(对大量数据传输不友好)。直接强制使用WebSocket,跳过不必要的协商步骤:

final httpConnectionOptions = HttpConnectionOptions(
  accessTokenFactory: () => SharedPreferenceService().loginWithToken(),
  headers: defaultHeaders,
  logger: transportProtLogger,
  logMessageContent: true,
  timeout: const Duration(seconds: 30),
  transport: HttpTransportType.webSockets, // 强制使用WebSocket
);

4. 分批次获取数据(核心优化)

如果数据量极大,一次性拉取极易超时或导致连接崩溃。建议后端将接口修改为分页/分批次模式,客户端循环获取:

List fixation = [];
int page = 1;
const pageSize = 200;
bool hasMore = true;

while (hasMore) {
  final batch = await hubConnection.invoke<List>(
    'GetBigStuffByPage',
    args: [page, pageSize],
    timeout: const Duration(minutes: 2),
  );
  if (batch == null || batch.isEmpty) {
    hasMore = false;
  } else {
    fixation.addAll(batch);
    page++;
  }
}

5. 添加自动重连机制

在HubConnectionBuilder中启用自动重连,避免意外断开后无法恢复连接:

final hubConnection = HubConnectionBuilder()
    .withUrl(
      'http://10.10/home',
      options: httpConnectionOptions,
    )
    .withAutomaticReconnect() // 启用自动重连
    .build();

修改后的完整代码示例

Future<List> fetchAllBugStuff() async {
  Logger.root.level = Level.ALL;
  Logger.root.onRecord.listen((LogRecord rec) {
    print('${rec.level.name}: ${rec.time}: ${rec.message}');
  });

  final transportProtLogger = Logger("SignalR - transport");

  Logger? logger;

  final httpConnectionOptions = HttpConnectionOptions(
    accessTokenFactory: () => SharedPreferenceService().loginWithToken(),
    headers: defaultHeaders,
    logger: transportProtLogger,
    logMessageContent: true,
    timeout: const Duration(seconds: 30),
    transport: HttpTransportType.webSockets,
  );

  final hubConnection = HubConnectionBuilder()
      .withUrl(
        'http://10.10/home',
        options: httpConnectionOptions,
      )
      .withAutomaticReconnect()
      .build();

  hubConnection.keepAliveIntervalInMilliseconds = 10 * 60 * 60 * 1000;
  hubConnection.onclose(({error}) {
    Logger.root.level = Level.SHOUT;
    Logger.root.onRecord.listen((LogRecord rec) {
      print('${rec.level.name}: ${rec.error}: ${rec.message}');
    });
    logger?.finer(error);
  });

  await hubConnection.start();
  List fixation = [];
  if (hubConnection.state == HubConnectionState.Connected) {
    // 若后端未调整接口,使用带超时的单次请求
    await hubConnection.invoke(
      'GetAllBigStuff',
      timeout: const Duration(minutes: 5),
    ).then((value) => fixation = value as List);

    // 若后端已支持分页,替换为以下循环逻辑
    // int page = 1;
    // const pageSize = 200;
    // bool hasMore = true;
    // while (hasMore) {
    //   final batch = await hubConnection.invoke<List>(
    //     'GetBigStuffByPage',
    //     args: [page, pageSize],
    //     timeout: const Duration(minutes: 2),
    //   );
    //   if (batch == null || batch.isEmpty) {
    //     hasMore = false;
    //   } else {
    //     fixation.addAll(batch);
    //     page++;
    //   }
    // }
  }

  return fixation;
}

内容的提问来源于stack exchange,提问作者user16357470

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 17:27:35