Flutter HTTP请求重复发送问题求助:Wi-Fi中断后队列残留导致重复请求
解决Flutter HTTP请求重复发送问题
针对你遇到的Wi-Fi断开后恢复点击按钮触发两次请求的问题,核心原因并非HTTP包的请求队列残留(原生http包默认不会缓存未发送的请求并自动重试),而是按钮未做状态控制导致重复点击,或未对未完成的请求做取消处理。以下是几种可行的解决方案:
1. 按钮状态控制(最简单直接)
点击按钮后立即禁用按钮,直到请求完全结束(成功/失败),从源头阻止重复点击:
在页面的State类中添加加载状态变量:
bool _isRequesting = false;
修改按钮的点击逻辑:
ElevatedButton( onPressed: _isRequesting ? null : () async { setState(() => _isRequesting = true); // 发起请求 final response = await _postJsonData(token, endpoint, object); // 处理响应逻辑... setState(() => _isRequesting = false); }, child: _isRequesting ? const CircularProgressIndicator(size: 20) : const Text('确认'), )
2. 取消未完成的请求(严格控制请求唯一性)
如果需要在用户再次点击时取消之前未完成的请求,确保始终只有最新的请求在执行,可以使用CancelableOperation:
在State类中维护当前请求的引用:
CancelableOperation? _currentRequest;
修改你的_postJsonData方法:
Future<dynamic> _postJsonData( String token, String endpoint, dynamic object) async { // 取消之前未完成的请求 _currentRequest?.cancel(); _currentRequest = CancelableOperation.fromFuture( http.post( Uri.https(_urlBase, endpoint), body: object.toJson(), headers: { 'Authorization': 'Bearer ' + token, 'Content-Type': 'application/json' }, ).catchError((e) { return http.Response( "{'error': true, 'mensaje': 'Ocurrió un problema en el servidor, intente nuevamente más tarde'}", 503, ); }), ); try { return await _currentRequest?.value; } finally { _currentRequest = null; } }
3. 切换到Dio包(更便捷的请求管理)
如果项目允许,使用dio包可以更方便地管理请求取消,它自带CancelToken机制:
先添加dio依赖:
dependencies: dio: ^5.4.0+1
修改请求方法:
CancelToken _cancelToken = CancelToken(); Future<dynamic> _postJsonData( String token, String endpoint, dynamic object) async { // 取消之前的请求 if (!_cancelToken.isCancelled) { _cancelToken.cancel('取消旧请求'); } _cancelToken = CancelToken(); try { final dioResponse = await Dio().post( 'https://$_urlBase/$endpoint', data: object.toJson(), options: Options( headers: { 'Authorization': 'Bearer ' + token, 'Content-Type': 'application/json', }, ), cancelToken: _cancelToken, ); return http.Response(dioResponse.data.toString(), dioResponse.statusCode!); } catch (e) { if (e is DioException && e.type == DioExceptionType.cancel) { return null; // 请求被取消,可根据业务处理 } return http.Response( "{'error': true, 'mensaje': 'Ocurrió un problema en el servidor, intente nuevamente más tarde'}", 503, ); } }
关键说明
- 原生
http包没有自动缓存未发送请求的逻辑,你遇到的重复请求大概率是重复点击按钮导致的,按钮状态控制足以解决大部分场景。 - 若必须确保请求唯一性,取消未完成请求的方案可以彻底避免同一时间存在多个待执行请求。
内容的提问来源于stack exchange,提问作者Luca Viotti
相关产品推荐
相关产品推荐

