|
@@ -0,0 +1,156 @@
|
|
|
|
|
+import 'dart:async';
|
|
|
|
|
+import 'dart:convert';
|
|
|
|
|
+import 'dart:io';
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+enum HttpClientStatus {
|
|
|
|
|
+ idle,
|
|
|
|
|
+ connecting,
|
|
|
|
|
+ connected,
|
|
|
|
|
+ disconnected,
|
|
|
|
|
+ error,
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+typedef HttpClientStatusHandler = void Function(HttpClientStatus status);
|
|
|
|
|
+
|
|
|
|
|
+class HttpClientWrap {
|
|
|
|
|
+ final Duration retryInterval;
|
|
|
|
|
+ final Map<String, String>? defaultHeaders;
|
|
|
|
|
+
|
|
|
|
|
+ HttpClient? _httpClient;
|
|
|
|
|
+ bool _disposed = false;
|
|
|
|
|
+
|
|
|
|
|
+ HttpClientStatus _status = HttpClientStatus.idle;
|
|
|
|
|
+ HttpClientStatus get status => _status;
|
|
|
|
|
+
|
|
|
|
|
+ final List<HttpClientStatusHandler> _statusHandlers = [];
|
|
|
|
|
+
|
|
|
|
|
+ HttpClientWrap({
|
|
|
|
|
+ this.retryInterval = const Duration(seconds: 5),
|
|
|
|
|
+ this.defaultHeaders,
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ /// 发送 GET 请求
|
|
|
|
|
+ Future<dynamic> get(String url, {Map<String, String>? headers, dynamic body}) async {
|
|
|
|
|
+ return _sendRequest(url, 'GET', headers: headers, body: body);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /// 发送 POST 请求
|
|
|
|
|
+ Future<dynamic> post(String url, {Map<String, String>? headers, dynamic body}) async {
|
|
|
|
|
+ return _sendRequest(url, 'POST', headers: headers, body: body);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /// 发送 PUT 请求
|
|
|
|
|
+ Future<dynamic> put(String url, {Map<String, String>? headers, dynamic body}) async {
|
|
|
|
|
+ return _sendRequest(url, 'PUT', headers: headers, body: body);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /// 发送 DELETE 请求
|
|
|
|
|
+ Future<dynamic> delete(String url, {Map<String, String>? headers}) async {
|
|
|
|
|
+ return _sendRequest(url, 'DELETE', headers: headers);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Future<dynamic> _sendRequest(
|
|
|
|
|
+ String url,
|
|
|
|
|
+ String method, {
|
|
|
|
|
+ Map<String, String>? headers,
|
|
|
|
|
+ dynamic body,
|
|
|
|
|
+ }) async {
|
|
|
|
|
+ if (_disposed) {
|
|
|
|
|
+ throw StateError('HTTP Client has been disposed');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ _updateStatus(HttpClientStatus.connecting);
|
|
|
|
|
+ _httpClient ??= HttpClient();
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+
|
|
|
|
|
+ late final Uri uri;
|
|
|
|
|
+ if ((method == 'GET') && (body != null)) {
|
|
|
|
|
+ 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 response = await request.close();
|
|
|
|
|
+ _updateStatus(HttpClientStatus.connected);
|
|
|
|
|
+
|
|
|
|
|
+ // 处理响应
|
|
|
|
|
+ final responseBody = await response.transform(utf8.decoder).join();
|
|
|
|
|
+ dynamic decodedResponse;
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ decodedResponse = jsonDecode(responseBody);
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ decodedResponse = responseBody;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Log.d('get response: $decodedResponse');
|
|
|
|
|
+
|
|
|
|
|
+ _updateStatus(HttpClientStatus.idle);
|
|
|
|
|
+ return decodedResponse; // 直接返回响应数据
|
|
|
|
|
+
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ _handleError(e);
|
|
|
|
|
+ _scheduleRetry();
|
|
|
|
|
+ rethrow; // 抛出异常以便调用方捕获
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /// 添加状态监听器
|
|
|
|
|
+ void addStatusListener(HttpClientStatusHandler handler) {
|
|
|
|
|
+ _statusHandlers.add(handler);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /// 移除状态监听器
|
|
|
|
|
+ void removeStatusListener(HttpClientStatusHandler handler) {
|
|
|
|
|
+ _statusHandlers.remove(handler);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /// 释放资源
|
|
|
|
|
+ Future<void> 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);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|