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

Dart HTTP服务器分块返回流数据时flush报错如何解决

Dart HTTP 服务实现分块流响应的正确方案

错误原因

你遇到的Bad state: StreamSink is bound to a stream报错由两个核心问题导致:

  • 手动设置Transfer-Encoding: chunked头属于多余操作:Dart 原生HttpServer在响应内容长度未知(传输流数据)时,会自动启用分块传输编码,手动设置该头会和框架内置逻辑冲突。
  • 手动监听流、无等待调用write+flush违反了IOSink的状态规则:HttpResponse的flush()是异步操作,上一次刷新未完成时再次调用写入/刷新方法,就会触发sink被占用的状态错误;同时这种写法没有做背压控制,流生产速度快于客户端接收速度时会撑爆服务器内存。

正确实现(和Go版本逻辑完全对齐)

直接使用addStream方法将音频流绑定到响应即可,框架会自动处理分块拆分、逐块刷新、背压控制、客户端断开时的流取消逻辑,不需要手动调用flush:

final server = await HttpServer.bind(InternetAddress.anyIPv4, 8080);
await for (var request in server) {
  final stream = await _audio.stream();
  final response = request.response;

  // 设置响应头,无需手动配置Transfer-Encoding
  response.headers
    ..contentType = ContentType("audio", "mpeg")
    ..add("Connection", "Keep-Alive")
    ..add("Access-Control-Allow-Origin", "*")
    ..add("X-Content-Type-Options", "nosniff");

  try {
    // 直接管道流到响应,自动逐块发送、自动flush
    await response.addStream(stream);
  } catch (e) {
    // 捕获客户端断开、流读取异常等场景
    print('传输中断: $e');
  } finally {
    // 传输完成/异常时关闭响应
    await response.close();
  }
}

特殊场景:需要逐块自定义处理的写法

如果需要在发送每个数据块前加自定义逻辑(比如日志、数据加工),不要直接在listen回调里无等待调用flush,需要通过暂停/恢复订阅做背压控制,等上一块发送完成再处理下一块:

final stream = await _audio.stream();
final response = request.response;
// 响应头配置和上文一致,省略
StreamSubscription? subscription;

subscription = stream.listen(
  (event) async {
    // 暂停订阅,防止当前块未发完就收到下一块数据
    subscription?.pause();
    response.add(event);
    // 等待数据刷新到客户端
    await response.flush();
    // 恢复订阅处理下一块
    subscription?.resume();
  },
  onError: (e) async {
    await response.close();
  },
  onDone: () async {
    await response.close();
  },
);

// 客户端主动断开时取消流订阅
response.done.then((_) => subscription?.cancel());

注意:非必要不使用这种手动写法,addStream内部已经实现了完整的背压、异常处理逻辑,稳定性更高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 06:09:26