连接池管理
- 使用
HttpClient
连接池:在Flutter中,http
插件底层基于HttpClient
。可以通过HttpClient
的connectionTimeout
、idleTimeout
等属性设置连接的超时时间,避免长时间占用连接资源。同时,利用HttpClient
内部的连接池机制,复用已有的连接,减少建立新连接的开销。例如:
import 'dart:io';
import 'package:http/http.dart' as http;
final client = http.Client();
// 使用自定义的HttpClient配置连接池
final httpClient = HttpClient()
..connectionTimeout = const Duration(seconds: 10)
..idleTimeout = const Duration(seconds: 20);
Future<http.Response> sendRequest(Uri url) async {
final request = await httpClient.getUrl(url);
final response = await request.close();
return http.Response.fromStream(response);
}
- 限制并发连接数:为了防止过多的并发请求导致网络资源耗尽,可以通过设置连接池的最大并发连接数。例如,在自定义的
HttpClient
实例中,可以通过maxConnectionsPerHost
属性设置每个主机的最大并发连接数。
final httpClient = HttpClient()
..maxConnectionsPerHost = 5;
缓存策略
- 内存缓存:在应用层实现简单的内存缓存。可以使用
Map
来存储请求的结果,每次发起请求前先检查缓存中是否有对应的响应。例如:
final Map<Uri, http.Response> memoryCache = {};
Future<http.Response> sendRequestWithCache(Uri url) async {
if (memoryCache.containsKey(url)) {
return memoryCache[url]!;
}
final response = await client.get(url);
memoryCache[url] = response;
return response;
}
- 磁盘缓存:对于较大的数据或者需要持久化的缓存,可以使用磁盘缓存。可以借助
path_provider
插件获取应用的本地存储路径,将响应数据以文件的形式存储在本地。每次请求时先检查磁盘缓存中是否有对应的文件,并且判断缓存是否过期。例如:
import 'package:path_provider/path_provider.dart';
import 'dart:io';
import 'package:http/http.dart' as http;
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
Future<File> _localFile(Uri url) async {
final path = await _localPath;
return File('$path/${url.hashCode}.cache');
}
Future<http.Response> sendRequestWithDiskCache(Uri url) async {
final file = await _localFile(url);
if (file.existsSync()) {
// 这里可以添加缓存过期判断逻辑
final responseBody = await file.readAsString();
return http.Response(responseBody, 200);
}
final response = await client.get(url);
await file.writeAsString(response.body);
return response;
}
请求队列控制
- 优先级队列:如果有不同优先级的网络请求,可以实现一个优先级队列。例如,使用
PriorityQueue
来管理请求。高优先级的请求优先处理,低优先级的请求在队列中等待。可以根据业务需求定义请求的优先级,比如实时数据请求优先级高于普通数据请求。
import 'dart:collection';
class Request {
final Uri url;
final int priority;
Request(this.url, this.priority);
}
final PriorityQueue<Request> requestQueue = PriorityQueue<Request>((a, b) => a.priority.compareTo(b.priority));
// 添加请求到队列
void addRequest(Uri url, int priority) {
requestQueue.add(Request(url, priority));
}
// 处理队列中的请求
Future<void> processQueue() async {
while (requestQueue.isNotEmpty) {
final request = requestQueue.removeFirst();
await client.get(request.url);
}
}
- 批量请求:对于一些可以合并的请求,将它们批量处理。例如,如果有多个获取用户信息的请求,可以将这些请求合并成一个批量获取用户信息的请求,减少网络请求次数。在请求队列中,可以根据请求的类型和参数判断是否可以合并,然后将合并后的请求发送出去。
// 假设请求用户信息的请求参数为用户ID列表
List<int> userIds = [1, 2, 3];
// 合并请求,假设后端有批量获取用户信息的接口
Uri batchUrl = Uri.parse('https://example.com/api/users?ids=${userIds.join(',')}');
await client.get(batchUrl);