import 'dart:async'; import 'dart:convert'; import 'dart:io'; enum HttpClientStatus { idle, connecting, connected, disconnected, error } typedef HttpClientStatusHandler = void Function(HttpClientStatus status); /// 单次请求的 HTTP 状态与解码正文,不共享并发请求状态。 class HttpClientWrapResponse { final int statusCode; final dynamic data; const HttpClientWrapResponse({required this.statusCode, required this.data}); } class HttpClientWrap { final Duration retryInterval; final Duration? connectionTimeout; final Duration? receiveTimeout; final Map? defaultHeaders; HttpClient? _httpClient; bool _disposed = false; HttpClientStatus _status = HttpClientStatus.idle; HttpClientStatus get status => _status; final List _statusHandlers = []; HttpClientWrap({ this.retryInterval = const Duration(seconds: 5), this.defaultHeaders, this.connectionTimeout, this.receiveTimeout, }); /// 发送 GET 请求 Future get( String url, { Map? headers, dynamic body, }) async { return _sendRequest(url, 'GET', headers: headers, body: body); } /// 发送 POST 请求 Future post( String url, { Map? headers, dynamic body, }) async { return _sendRequest(url, 'POST', headers: headers, body: body); } /// 发送 PUT 请求 Future put( String url, { Map? headers, dynamic body, }) async { return _sendRequest(url, 'PUT', headers: headers, body: body); } /// 发送 DELETE 请求 Future delete(String url, {Map? headers}) async { return _sendRequest(url, 'DELETE', headers: headers); } Future _sendRequest( String url, String method, { Map? headers, dynamic body, }) async { return (await request(url, method, headers: headers, body: body)).data; } /// 返回 HTTP 状态与正文;旧 get/post/put/delete 仍仅返回正文。 Future request( String url, String method, { Map? headers, dynamic body, }) async { if (_disposed) { throw StateError('HTTP Client has been disposed'); } _updateStatus(HttpClientStatus.connecting); _httpClient ??= HttpClient()..connectionTimeout = connectionTimeout; try { late final Uri uri; if ((method == 'GET') && (body != null)) { // queryParameters Map value 只接受 String 和 List 两种类型 // final queryParams = body.map((key, value) { // if (value is Iterable) { // // 多值:转成 List // return MapEntry(key, value.map((v) => v.toString()).toList()); // } else { // // 单值:转成 String // return MapEntry(key, value.toString()); // } // }); final queryParams = {}; if (body is Map) { body.forEach((key, value) { if (value is Iterable) { // 多值:转成 List queryParams[key.toString()] = value .map((v) => v.toString()) .toList(); } else { // 单值:转成 String queryParams[key.toString()] = value.toString(); } }); } uri = Uri.parse(url).replace(queryParameters: queryParams); // uri = Uri.parse(url).replace( // queryParameters: body, // ); } else { uri = Uri.parse(url); } final request = await _httpClient!.openUrl(method, uri); // 设置请求头 final mergedHeaders = {...?defaultHeaders, ...?headers}; mergedHeaders.forEach((key, value) { request.headers.set(key, value); }); // 添加请求体(如果是POST/PUT) if (body != null && (method == 'POST' || method == 'PUT')) { if (body is Map || body is List) { request.write(jsonEncode(body)); } else { request.write(body.toString()); } } final responseFuture = request.close(); final timeout = receiveTimeout; final response = await (timeout == null ? responseFuture : responseFuture.timeout(timeout)); _updateStatus(HttpClientStatus.connected); // 处理响应 final responseStream = response.transform(utf8.decoder); final responseBody = await (timeout == null ? responseStream : responseStream.timeout(timeout)) .join(); dynamic decodedResponse; try { decodedResponse = jsonDecode(responseBody); } catch (e) { decodedResponse = responseBody; } // Log.d('get response: $decodedResponse'); _updateStatus(HttpClientStatus.idle); return HttpClientWrapResponse( statusCode: response.statusCode, data: decodedResponse, ); } catch (e) { _handleError(e); // _scheduleRetry(); _resetClient(); rethrow; // 抛出异常以便调用方捕获 } } /// 添加状态监听器 void addStatusListener(HttpClientStatusHandler handler) { _statusHandlers.add(handler); } /// 移除状态监听器 void removeStatusListener(HttpClientStatusHandler handler) { _statusHandlers.remove(handler); } void _resetClient() { _httpClient?.close(force: true); _httpClient = null; } /// 释放资源 Future dispose() async { _disposed = true; _httpClient?.close(); _httpClient = null; _statusHandlers.clear(); _updateStatus(HttpClientStatus.disconnected); } void _handleError(dynamic error) { _updateStatus(HttpClientStatus.error); } void _scheduleRetry() { if (_disposed) return; Timer(retryInterval, () { _updateStatus(HttpClientStatus.idle); }); } void _updateStatus(HttpClientStatus status) { _status = status; for (final handler in _statusHandlers) { handler(status); } } }