Dart中http.send抛出的Connection closed while receiving data异常如何捕获?
异常未捕获的核心原因
- 同步
try/catch无法捕获异步方法抛出的异常,_client.send(request)返回异步Future,其产生的异常不会进入同步捕获逻辑 response.catchError会返回一个新的处理过异常的Future,你没有持有和使用这个返回值,原Future的异常依旧会抛出- 你为response设置的
onError回调里又把异常重新抛出,相当于没有处理异常 response.asStream().listen()未配置onError回调,数据流的错误会直接作为未处理异常抛出,就是你看到的报错来源
修复实现方案
你可以直接在stream的listen方法中添加onError回调捕获连接异常,同时添加重连逻辑,完整代码参考如下:
import 'dart:math'; // 定义全局控制参数,避免销毁后重复重连 bool _shouldReconnect = true; int _retryCount = 0; http.Client? _client; StreamSubscription? _streamSubscription; Future<void> connectSse(String url) async { try { // 每次连接前清理旧的资源 _client?.close(); await _streamSubscription?.cancel(); _client = http.Client(); var request = http.Request("GET", Uri.parse(url)); request.headers["Cache-Control"] = "no-cache"; request.headers["Accept"] = "text/event-stream"; final response = await _client!.send(request); // 连接成功重置重试次数 _retryCount = 0; _streamSubscription = response.stream.listen( (data) { // 原有服务端事件处理逻辑 }, onError: (e) { Log.e("连接出现异常: $e"); _triggerReconnect(url); }, onDone: () { Log.e("连接已断开"); _triggerReconnect(url); }, cancelOnError: false, // 错误时不自动取消订阅,方便自行控制重连逻辑 ); } catch (e) { Log.e("建立连接失败: $e"); _triggerReconnect(url); } } void _triggerReconnect(String url) { if (!_shouldReconnect) return; // 重试间隔递增,最多间隔30秒,避免频繁请求压垮服务端 final delay = Duration(seconds: min(_retryCount * 2, 30)); _retryCount++; Future.delayed(delay, () => connectSse(url)); } // 页面销毁/主动断开连接时调用,避免不必要的重连 void disposeSse() { _shouldReconnect = false; _client?.close(); _streamSubscription?.cancel(); }
注意事项
- 主动断开连接时要把
_shouldReconnect置为false,避免不需要重连的场景下反复发起请求 - 每次重连前必须关闭旧的http client和订阅,避免资源泄漏
- 可以根据业务需求调整重试间隔的上限和递增规则
内容的提问来源于stack exchange,提问作者MarcS82
相关产品推荐
相关产品推荐

