| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- 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<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,
- this.connectionTimeout,
- this.receiveTimeout,
- });
- /// 发送 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 {
- return (await request(url, method, headers: headers, body: body)).data;
- }
- /// 返回 HTTP 状态与正文;旧 get/post/put/delete 仍仅返回正文。
- Future<HttpClientWrapResponse> request(
- 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()..connectionTimeout = connectionTimeout;
- try {
- late final Uri uri;
- if ((method == 'GET') && (body != null)) {
- // queryParameters Map value 只接受 String 和 List<String> 两种类型
- // final queryParams = body.map((key, value) {
- // if (value is Iterable) {
- // // 多值:转成 List<String>
- // return MapEntry(key, value.map((v) => v.toString()).toList());
- // } else {
- // // 单值:转成 String
- // return MapEntry(key, value.toString());
- // }
- // });
- final queryParams = <String, dynamic>{};
- if (body is Map) {
- body.forEach((key, value) {
- if (value is Iterable) {
- // 多值:转成 List<String>
- 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<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);
- }
- }
- }
|