如何捕获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
相关产品推荐
相关产品推荐

