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

如何捕获HTTP请求超时后send()方法抛出的嵌套异常?

如何捕获POST请求超时后send()抛出的二次异常?

我给POST请求设置了超时时间,请求挂起时,超时异常能被catch块正常捕获,但几秒后send()方法会抛出另一个包含实际问题的异常(官方文档提到该方法会重抛出异常)。这时候控制流已经退出try-catch块了,请问怎么捕获这个二次嵌套异常?

原代码示例:

final request = http.MultipartRequest('POST', uri);
try {
  final response = await request.send().timeout(Duration(seconds: 2));
} on TimeoutException {
  logger.d("Request failed by timing out!"); // 能可靠捕获2秒超时
} catch (e) {
  logger.d('An error occurred: $e');
}

问题根源

timeout方法只是终止了等待响应的Future,但底层的send()请求并没有被取消,当它后续完成(成功或失败)时,会抛出未被捕获的异常,此时原try-catch块已经执行完毕,所以无法捕获。

解决办法

1. 改用Dio库(推荐,支持请求取消)

Dio内置了请求取消和超时管理,能彻底终止底层请求,避免后续异常:

import 'package:dio/dio.dart';

final cancelToken = CancelToken();
try {
  final response = await Dio().post(
    uri.toString(),
    cancelToken: cancelToken,
    options: Options(
      sendTimeout: 2000, // 发送超时
      receiveTimeout: 2000, // 接收超时
    ),
  );
} on DioException catch (e) {
  if (e.type == DioExceptionType.cancel) {
    logger.d("请求已取消");
  } else if (e.type == DioExceptionType.connectionTimeout || e.type == DioExceptionType.receiveTimeout) {
    logger.d("请求超时");
  } else {
    logger.d("发生错误: $e");
  }
}

2. 原生http包的兜底处理

原生http包没有公开的请求取消接口,但可以通过提前捕获send()的所有异常,确保不会有漏网的未捕获异常:

final request = http.MultipartRequest('POST', uri);
try {
  // 先捕获send的异常,再套timeout,确保所有异常进入外层catch
  final response = await request.send()
      .catchError((err) => throw err)
      .timeout(Duration(seconds: 2));
} on TimeoutException {
  logger.d("请求超时失败!");
} catch (e) {
  logger.d("发生错误: $e");
}

不过这种方法只能捕获异常,无法真正终止底层请求,请求仍会在后台完成,只是不会导致程序崩溃。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 19:47:19