Initial commit: Flutter 无书应用项目
This commit is contained in:
218
lib/utils/http/http_client.dart
Normal file
218
lib/utils/http/http_client.dart
Normal file
@@ -0,0 +1,218 @@
|
||||
/// 时间: 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请求
|
||||
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,
|
||||
);
|
||||
}
|
||||
|
||||
/// 通用请求方法
|
||||
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');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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';
|
||||
}
|
||||
Reference in New Issue
Block a user