Files
wushu/lib/utils/http/http_client.dart
2026-03-30 07:32:12 +08:00

319 lines
8.1 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/// 时间: 2025-03-21
/// 功能: HTTP客户端工具类使用纯Dart dio库
/// 介绍: 提供统一的HTTP请求方法支持GET、POST等请求用于项目中的网络请求
/// 最新变化: 移除CORS代理需后台服务器配置CORS响应头
import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
class HttpClient {
static const String _baseUrl = 'https://yy.vogov.cn/api/';
static const Duration _timeout = Duration(seconds: 30);
static final BaseOptions _options = BaseOptions(
baseUrl: _baseUrl,
connectTimeout: _timeout,
receiveTimeout: _timeout,
sendTimeout: _timeout,
headers: {
'Content-Type': 'application/json; charset=UTF-8',
'Accept': 'application/json',
'User-Agent': 'Poes-Flutter/1.0.0',
},
);
static final Dio _dio = Dio(_options);
/// 添加调试日志
static void _debugLog(String message) {
if (kDebugMode) {
print('HttpClient: $message');
}
}
/// GET请求
static Future<HttpResponse> get(
String path, {
Map<String, dynamic>? queryParameters,
Map<String, String>? headers,
Duration? timeout,
}) async {
return _request(
'GET',
path,
queryParameters: queryParameters,
headers: headers,
timeout: timeout,
);
}
/// POST请求 - JSON格式
static Future<HttpResponse> post(
String path, {
Map<String, dynamic>? data,
Map<String, String>? headers,
Duration? timeout,
}) async {
return _request(
'POST',
path,
data: data,
headers: headers,
timeout: timeout,
);
}
/// POST请求 - FormData格式
static Future<HttpResponse> postForm(
String path, {
Map<String, dynamic>? data,
Map<String, String>? headers,
Duration? timeout,
}) async {
return _requestForm(
'POST',
path,
data: data,
headers: headers,
timeout: timeout,
);
}
/// 通用请求方法 - JSON格式
static Future<HttpResponse> _request(
String method,
String path, {
Map<String, dynamic>? queryParameters,
Map<String, dynamic>? data,
Map<String, String>? headers,
Duration? timeout,
}) async {
try {
final url = '$_baseUrl$path';
_debugLog('请求 $method $url');
if (queryParameters != null) {
_debugLog('查询参数: $queryParameters');
}
final options = Options(
method: method,
headers: headers != null
? {..._options.headers!, ...headers}
: _options.headers,
);
if (timeout != null) {
options.connectTimeout = timeout;
options.receiveTimeout = timeout;
options.sendTimeout = timeout;
}
Response response;
if (method.toUpperCase() == 'GET') {
response = await _dio.get(
url,
queryParameters: queryParameters,
options: options,
);
} else if (method.toUpperCase() == 'POST') {
response = await _dio.post(
url,
data: data,
queryParameters: queryParameters,
options: options,
);
} else {
throw UnsupportedError('HTTP method $method is not supported');
}
_debugLog('响应状态: ${response.statusCode}');
_debugLog('响应数据: ${response.data}');
return HttpResponse(
statusCode: response.statusCode ?? 0,
body: response.data is String
? response.data
: json.encode(response.data),
headers: response.headers.map.cast<String, String>(),
);
} on DioException catch (e) {
_debugLog('Dio异常: ${e.type} - ${e.message}');
String message;
switch (e.type) {
case DioExceptionType.connectionTimeout:
case DioExceptionType.sendTimeout:
case DioExceptionType.receiveTimeout:
message = '请求超时,请检查网络连接';
break;
case DioExceptionType.connectionError:
message = '网络连接失败,请检查网络设置';
break;
case DioExceptionType.badResponse:
message = '服务器错误: ${e.response?.statusCode} - ${e.response?.data}';
break;
default:
message = '请求失败: ${e.message}';
}
throw HttpException(message);
} catch (e) {
_debugLog('未知异常: $e');
throw HttpException('请求失败:$e');
}
}
/// FormData格式请求方法
static Future<HttpResponse> _requestForm(
String method,
String path, {
Map<String, dynamic>? queryParameters,
Map<String, dynamic>? data,
Map<String, String>? headers,
Duration? timeout,
}) async {
try {
final url = '$_baseUrl$path';
_debugLog('FormData请求 $method $url');
if (queryParameters != null) {
_debugLog('查询参数: $queryParameters');
}
if (data != null) {
_debugLog('表单数据: $data');
}
final formData = FormData.fromMap(data ?? {});
final options = Options(
method: method,
headers: headers != null
? {..._options.headers!, ...headers}
: _options.headers,
);
options.headers?['Content-Type'] = 'multipart/form-data';
if (timeout != null) {
options.connectTimeout = timeout;
options.receiveTimeout = timeout;
options.sendTimeout = timeout;
}
Response response;
if (method.toUpperCase() == 'POST') {
response = await _dio.post(
url,
data: formData,
queryParameters: queryParameters,
options: options,
);
} else {
throw UnsupportedError('FormData only supports POST method');
}
_debugLog('响应状态: ${response.statusCode}');
_debugLog('响应数据: ${response.data}');
return HttpResponse(
statusCode: response.statusCode ?? 0,
body: response.data is String
? response.data
: json.encode(response.data),
headers: response.headers.map.cast<String, String>(),
);
} on DioException catch (e) {
_debugLog('Dio异常: ${e.type} - ${e.message}');
String message;
switch (e.type) {
case DioExceptionType.connectionTimeout:
case DioExceptionType.sendTimeout:
case DioExceptionType.receiveTimeout:
message = '请求超时,请检查网络连接';
break;
case DioExceptionType.connectionError:
message = '网络连接失败,请检查网络设置';
break;
case DioExceptionType.badResponse:
message = '服务器错误: ${e.response?.statusCode} - ${e.response?.data}';
break;
default:
message = '请求失败: ${e.message}';
}
throw HttpException(message);
} catch (e) {
_debugLog('未知异常: $e');
throw HttpException('请求失败:$e');
}
}
}
/// HTTP响应类
class HttpResponse {
final int statusCode;
final String body;
final Map<String, String> headers;
HttpResponse({
required this.statusCode,
required this.body,
required this.headers,
});
/// 是否成功 (2xx状态码)
bool get isSuccess => statusCode >= 200 && statusCode < 300;
/// 解析JSON响应
Map<String, dynamic> get jsonData {
try {
return json.decode(body) as Map<String, dynamic>;
} catch (e) {
throw FormatException('Invalid JSON response: $body');
}
}
/// 获取响应消息
String get message {
if (isSuccess) {
try {
return jsonData['msg'] ?? 'Success';
} catch (e) {
return 'Success';
}
} else {
return body;
}
}
/// 获取响应数据
dynamic get data {
if (isSuccess) {
return jsonData['data'];
}
return null;
}
/// 获取响应代码
int get code {
if (isSuccess) {
try {
return jsonData['code'] ?? 0;
} catch (e) {
return 0;
}
}
return statusCode;
}
}
/// HTTP异常类
class HttpException implements Exception {
final String message;
const HttpException(this.message);
@override
String toString() => 'HttpException: $message';
}