Flutter应用调用REST API遇HandshakeException问题求助
问题分析
你碰到的两个问题是独立的核心点:
- 组件无法渲染:
forEach配合async回调的写法有问题——forEach不会等待内部的异步请求完成,导致fetchAndSetWorkOrders方法提前结束,loadedWorkOrders还没填充数据就返回了,组件自然拿不到有效数据。 - 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
相关产品推荐
相关产品推荐

