在Flutter中利用Future.wait规避API请求超限问题
解决Flutter API调用触发DDOS防护限制的问题
原代码的问题
你当前的代码逻辑完全无法实现限流效果:Future.wait会一次性发起所有异步请求,根本做不到分批或控速;而且antiSpam变量在多个并发的异步回调里被同时修改,计数逻辑完全不可靠——多个异步函数会同时读写这个变量,导致判断条件彻底失效。
方案一:分批次请求(严格控制每秒20次)
把请求按每20个一组拆分,每组请求完成后等待1秒再发起下一组,完美匹配服务器的限流规则:
// 查询Token信息 final tokenMap = <String, Token>{}; final uniqueAddresses = tokenAddressList.toSet().toList(); const batchSize = 20; for (int i = 0; i < uniqueAddresses.length; i += batchSize) { // 截取当前批次的地址(避免越界) final endIndex = min(i + batchSize, uniqueAddresses.length); final batch = uniqueAddresses.sublist(i, endIndex); // 发起当前批次的所有请求 final batchResults = await Future.wait( batch.map((address) => sl.get<ApiService>().getToken([address])), ); // 将结果存入map for (int j = 0; j < batch.length; j++) { tokenMap[batch[j]] = batchResults[j]; } // 非最后一批次,等待1秒再继续 if (endIndex < uniqueAddresses.length) { await Future.delayed(const Duration(seconds: 1)); } }
方案二:匀速控速(请求分布更平滑)
如果不想等整批完成再等待,可以让请求均匀分布在时间里,比如每50毫秒发起一个请求(刚好每秒20次),避免瞬间请求峰值:
// 查询Token信息 final tokenMap = <String, Token>{}; final uniqueAddresses = tokenAddressList.toSet().toList(); const requestInterval = Duration(milliseconds: 50); // 1秒20次,单次间隔50ms for (int i = 0; i < uniqueAddresses.length; i++) { final address = uniqueAddresses[i]; final token = await sl.get<ApiService>().getToken([address]); tokenMap[address] = token; // 非最后一个请求,等待间隔时间 if (i != uniqueAddresses.length - 1) { await Future.delayed(requestInterval); } }
额外优化建议
如果你的API支持批量查询(比如一次传入多个token地址),优先使用批量接口——这能直接把n次请求压缩成少数几次,从根本上规避限流问题,效率也会更高。
内容的提问来源于stack exchange,提问作者redDwarf
相关产品推荐
相关产品推荐

