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

Flutter应用调用REST API遇HandshakeException问题求助

问题分析

你碰到的两个问题是独立的核心点:

  1. 组件无法渲染:forEach配合async回调的写法有问题——forEach不会等待内部的异步请求完成,导致fetchAndSetWorkOrders方法提前结束,loadedWorkOrders还没填充数据就返回了,组件自然拿不到有效数据。
  2. HandshakeException握手错误:大概率是一次性发起过多并发请求触发了服务器/客户端的连接限制,或是API的TLS配置和Flutter默认HTTP客户端不兼容。

解决方案

1. 修复异步循环逻辑,确保数据加载完成

把forEach替换成for循环或Future.wait,保证所有子请求完成后再结束方法:

方式一:for循环逐个处理(适合请求数量不多的场景)

Future<void> fetchAndSetWorkOrders([bool filterByUser = false]) async {
  var url = Uri.parse(
      'https://API_URL/wo?fields=id,code,description,statusCode,actionType,assignedTo&filter[wo][statusCode]=REQUEST');
  try {
    var response = await http.get(
      url,
      headers: {
        "token": authToken,
      },
    );
    var extractedData = json.decode(response.body) as Map<String, dynamic>;
    final List<WorkOrder> loadedWorkOrders = [];
    
    if (extractedData['data'] == null) {
      return;
    }

    // 替换forEach为for循环,确保每个异步请求完成后再继续执行
    for (final attribute in extractedData['data']) {
      var actionType_url = Uri.parse(attribute['relationships']
              ['actionType']['links']['related']);

      var actionType_response = await http.get(
        actionType_url,
        headers: {
          "token": authToken,
        },
      );

      var actionTypeData = json.decode(actionType_response.body) as dynamic;
      var actionType_code = actionTypeData['data']['attributes']['code'];
      print(actionType_code);
      loadedWorkOrders.add(
        WorkOrder(
          id: attribute['id'],
          code: attribute['attributes']['code'],
          description: attribute['attributes']['description'],
          statusCode: attribute['attributes']['statusCode'],
          actionType: actionType_code,
        ),
      );
    }
    // 这里记得将loadedWorkOrders赋值给你的数据源(比如状态管理中的变量)
  } catch (e) {
    // 捕获异常避免APP崩溃,同时便于排查问题
    print(e);
    rethrow;
  }
}

方式二:Future.wait批量处理(效率更高,适合多请求场景)

Future<void> fetchAndSetWorkOrders([bool filterByUser = false]) async {
  var url = Uri.parse(
      'https://API_URL/wo?fields=id,code,description,statusCode,actionType,assignedTo&filter[wo][statusCode]=REQUEST');
  try {
    var response = await http.get(
      url,
      headers: {
        "token": authToken,
      },
    );
    var extractedData = json.decode(response.body) as Map<String, dynamic>;
    
    if (extractedData['data'] == null) {
      return;
    }

    // 生成所有子请求的Future列表
    final futures = extractedData['data'].map((attribute) async {
      var actionType_url = Uri.parse(attribute['relationships']
              ['actionType']['links']['related']);

      var actionType_response = await http.get(
        actionType_url,
        headers: {
          "token": authToken,
        },
      );

      var actionTypeData = json.decode(actionType_response.body) as dynamic;
      var actionType_code = actionTypeData['data']['attributes']['code'];
      return WorkOrder(
        id: attribute['id'],
        code: attribute['attributes']['code'],
        description: attribute['attributes']['description'],
        statusCode: attribute['attributes']['statusCode'],
        actionType: actionType_code,
      );
    }).toList();

    // 等待所有请求完成,一次性拿到所有WorkOrder数据
    final loadedWorkOrders = await Future.wait(futures);
    // 赋值给数据源
  } catch (e) {
    print(e);
    rethrow;
  }
}

2. 解决HandshakeException握手异常

情况一:并发请求过多

如果用Future.wait一次性发起大量请求,可能触发服务器的连接限制。可以限制并发数,比如借助package:async的工具类实现分批处理,或者自己手动拆分请求列表分批执行。

情况二:证书/SSL问题(仅开发环境使用)

如果API使用自签名证书,开发阶段可以自定义HTTP客户端忽略证书验证:

import 'dart:io';
import 'package:http/http.dart' as http;

// 创建忽略证书验证的客户端
final client = HttpClient()
  ..badCertificateCallback = ((X509Certificate cert, String host, int port) => true);
final httpClient = http.IOClient(client);

// 使用该客户端发起请求
var response = await httpClient.get(url, headers: {"token": authToken});

⚠️ 注意:生产环境绝对不能这么做,会带来严重安全风险,必须使用合法可信的SSL证书。

情况三:TLS版本不兼容

部分旧API仅支持TLS 1.0/1.1,而Flutter默认禁用了这些旧版本,可手动启用:

import 'dart:io';

HttpClient client = HttpClient();
client.context.setAlpnProtocols(['http/1.1', 'tls1', 'tls1.1', 'tls1.2'], false);
final httpClient = http.IOClient(client);

额外提醒

  • 务必添加异常捕获逻辑,避免未处理的异常导致APP崩溃。
  • 如果API支持,优先要求后端一次性返回关联数据(比如第一个请求就包含actionType的信息),减少多次请求的开销和潜在问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 04:35:18