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

Dart/Flutter如何为WebSocket、HttpClient、Socket模拟弱网断网

Dart/Flutter 模拟弱网、断网场景方案说明

你提出的装饰器代理Socket方案可行性

这个思路完全可行,属于可控性很高的自定义实现方案,核心逻辑没有硬伤,但实际写的时候要注意几个容易漏的点:

  • 不要只给add方法加延迟:Socket是全双工通信通道,只加上行发送的延迟,只能模拟上传慢,下行接收数据、连接建立握手、连接关闭的流程都要加对应延迟,才和真实弱网表现一致。
  • 断网场景不要靠超长延迟模拟:模拟无网络时,直接在对应逻辑里抛出SocketException、提前关闭流触发错误回调即可,不要等延迟走完再调用真实Socket的方法。
  • 不用硬抠所有接口的手动实现:Socket本身继承了Stream、IOSink,带的方法和属性很多,手动全写很容易漏,除了你要修改的核心收发方法,剩下的方法可以直接代理到真实Socket实例,嫌麻烦甚至可以用noSuchMethod做兜底,避免出现未实现的运行时错误。
  • HttpClient、WebSocket不需要单独写装饰器:这俩上层API底层都是走Socket通信,只要能把你自定义的SlowSocket注入到客户端的创建链路里,上层的HTTP请求、WebSocket连接会自动走你模拟的弱网逻辑,不用重复写代理代码。

更省成本的实现选择

如果不想从零写Socket代理,也可以根据自己的场景选更简单的方案:

  • 只需要模拟普通HTTP接口的弱网:直接用HttpOverrides全局重写HttpClient创建逻辑就行,在自定义的HttpClient里给请求发送、响应接收加延迟、抛异常,不需要碰Socket层,几十行代码就能覆盖大部分应用层接口测试需求。
  • 需要覆盖Socket、WebSocket全场景,不想改业务代码:可以在测试环境配本地代理,把所有设备/模拟器的网络请求指向本地代理服务,在代理层统一配置延迟、丢包、带宽限制、断网规则,这种方式对业务代码零侵入,还能模拟随机抖动、高丢包这些自己写装饰器很难还原的真实弱网特征。
  • 只用于单元测试:直接给网络层依赖传Mock实例就行,不需要走真实网络连接,在Mock类里自定义返回延迟、错误逻辑,实现成本最低。

自定义SlowSocket核心逻辑参考

import 'dart:async';
import 'dart:io';

class SlowSocket implements Socket {
  final Socket _realSocket;
  // 模拟网络延迟,单位毫秒
  final int networkDelayMs;
  // 模拟网络错误概率,取值0-1
  final double errorRate;

  SlowSocket(
    this._realSocket, {
    this.networkDelayMs = 1500,
    this.errorRate = 0,
  });

  // 统一的网络模拟逻辑
  Future<T> _applyNetworkRule<T>(Future<T> Function() realAction) async {
    await Future.delayed(Duration(milliseconds: networkDelayMs));
    // 按概率抛出网络异常模拟断网/丢包
    if (errorRate > 0 && DateTime.now().microsecondsSinceEpoch % 1000 < errorRate * 1000) {
      throw const SocketException('Network unreachable');
    }
    return realAction();
  }

  @override
  void add(List<int> data) {
    _applyNetworkRule(() async {
      _realSocket.add(data);
    });
  }

  @override
  StreamSubscription<List<int>> listen(
    void Function(List<int> event)? onData, {
    Function? onError,
    void Function()? onDone,
    bool? cancelOnError,
  }) {
    // 下行数据同样套网络规则
    return _realSocket
        .asyncMap((dataChunk) async {
          await Future.delayed(Duration(milliseconds: networkDelayMs));
          if (errorRate > 0 && DateTime.now().microsecondsSinceEpoch % 1000 < errorRate * 1000) {
            throw const SocketException('Network receive error');
          }
          return dataChunk;
        })
        .listen(
          onData,
          onError: onError,
          onDone: onDone,
          cancelOnError: cancelOnError,
        );
  }

  // 其余Socket接口方法直接代理真实实例即可,IDE可一键生成,也可用noSuchMethod兜底
  @override
  noSuchMethod(Invocation invocation) => Function.apply(
        _realSocket.noSuchMethod,
        [invocation],
      );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.14 16:15:48