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

Flutter中发送GraphQL查询后未收到响应前如何中止请求?

Flutter GraphQL 主动中止未完成查询请求实现方案

你当前使用的自定义查询函数参考:
发送查询所用函数

要实现提交查询后、收到响应前主动中止的功能,直接按下面的步骤改造即可:

方案一:基于网络层真实取消(推荐)

这个方案会真正断开和服务端的网络连接,不浪费带宽,是生产环境优先选择的实现。

  • 前置说明:如果你的GraphQL链路用的是DioLink(绝大多数Flutter GraphQL项目都会用Dio替换默认http实现,方便加拦截器、日志、证书校验等能力),不需要额外改链路配置;如果当前用的是默认HttpLink,只需要把链路替换为DioLink即可,替换成本极低。
  • 第一步:改造你的自定义查询函数,增加取消令牌参数
// 引入dio的取消令牌,需要在pubspec.yaml添加依赖:dio: ^5.4.0
import 'package:dio/dio.dart';

Future<QueryResult> customQuery(
  String query, {
  Map<String, dynamic>? variables,
  FetchPolicy? fetchPolicy,
  // 新增可选取消令牌参数
  CancelToken? cancelToken,
}) async {
  final QueryOptions options = QueryOptions(
    document: gql(query),
    variables: variables ?? const {},
    fetchPolicy: fetchPolicy ?? FetchPolicy.networkOnly,
    // 将取消令牌传入请求上下文,DioLink会自动识别并绑定到请求上
    context: {
      'cancelToken': cancelToken,
    },
  );
  return await client.query(options);
}
  • 第二步:业务层调用时管理取消令牌,需要中止时触发取消
// 声明页级别的取消令牌实例
CancelToken? _queryCancelToken;

/// 发起查询请求
void fetchListData() async {
  // 发起新请求前先取消上一次未完成的请求,避免重复请求、数据错乱
  _queryCancelToken?.cancel("触发新请求,自动中止旧请求");
  _queryCancelToken = CancelToken();

  try {
    final result = await customQuery(
      r'''
        query GetList($page: Int!) {
          list(page: $page) {
            id
            title
          }
        }
      ''',
      variables: {"page": 1},
      cancelToken: _queryCancelToken,
    );

    // 正常响应处理
    if (result.data != null && !result.hasException) {
      // 渲染数据逻辑
    }
  } catch (e) {
    // 单独识别主动取消的异常,不需要弹出错误提示
    if (e is OperationCanceledException || (e is DioException && e.type == DioExceptionType.cancel)) {
      print("请求已主动中止");
      return;
    }
    // 其他常规错误处理:网络错误、服务端报错等
    print("请求出错:$e");
  }
}

/// 主动中止请求的触发方法,可以绑定到取消按钮点击、返回事件等
void stopRunningQuery() {
  _queryCancelToken?.cancel("用户主动取消请求");
  _queryCancelToken = null;
}

@override
void dispose() {
  // 页面销毁时必须中止未完成请求,避免内存泄漏、回调执行报错
  stopRunningQuery();
  super.dispose();
}

方案二:零链路改造快速实现

如果你不想改动现有GraphQL链路配置,可以用Dart异步包装的方式实现业务层的请求中止,注意这个方案不会真正断开底层网络连接,只是会中断业务层的回调执行,适合快速迭代的场景。

  • 第一步:添加async工具包依赖:async: ^2.11.0
  • 第二步:用可取消异步对象包装请求
import 'package:async/async.dart';

// 声明可取消操作实例
CancelableOperation<QueryResult>? _cancelableQuery;

void fetchListData() async {
  // 取消上一次未完成操作
  _cancelableQuery?.cancel();

  // 包装原有查询请求为可取消操作
  _cancelableQuery = CancelableOperation.fromFuture(
    customQuery(
      r'''
        query GetList($page: Int!) {
          list(page: $page) {
            id
            title
          }
        }
      ''',
      variables: {"page": 1},
    ),
  );

  try {
    final result = await _cancelableQuery?.value;
    if (result != null && result.data != null && !result.hasException) {
      // 数据渲染逻辑
    }
  } catch (e) {
    // 常规错误处理
  }
}

// 主动中止调用
void stopRunningQuery() {
  _cancelableQuery?.cancel();
  _cancelableQuery = null;
}

@override
void dispose() {
  stopRunningQuery();
  super.dispose();
}

补充:如果是Mutation请求需要中止,改造逻辑和上面完全一致,只需要把client.query换成client.mutate,QueryOptions换成MutationOptions即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 03:45:46