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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 10:43:17