starwork_flutter/lib/api/base_api_service.dart

152 lines
5.4 KiB
Dart
Raw Normal View History

import 'package:dio/dio.dart' as dioAlias;
import 'package:dio/dio.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:starwork_flutter/api/api_response.dart';
import 'package:starwork_flutter/base/app_logger.dart';
import 'package:starwork_flutter/common/constant/app_toast_messages.dart';
import 'package:starwork_flutter/common/constant/cache_keys.dart';
import 'package:starwork_flutter/common/constant/http_constant.dart';
import 'package:starwork_flutter/common/utils/shared_preferences_utils.dart';
import 'package:starwork_flutter/flavors.dart';
import 'package:flutter/foundation.dart'; // 用于 debugPrint
class BaseApiService {
final dioAlias.Dio dio = dioAlias.Dio();
BaseApiService() {
dio.options.baseUrl = F.apiHost;
dio.options.connectTimeout = const Duration(seconds: 30);
dio.options.receiveTimeout = const Duration(seconds: 30);
2025-09-12 10:35:07 +08:00
dio.options.headers['content-type'] = 'application/json';
// 添加拦截器
dio.interceptors.add(InterceptorsWrapper(
onRequest: (options, handler) {
var token = SharedPreferencesUtils.getString(CacheKeys.token);
if (token != null) {
options.headers['Authorization'] = 'Bearer $token';
}
/// 请求拦截器
return handler.next(options);
},
onResponse: (response, handler) {
/// 响应拦截器
return handler.next(response);
},
onError: (DioError e, handler) {
// 异常拦截器
return handler.next(e);
},
));
}
/// 统一请求方法
Future<ApiResponse<T>> makeRequest<T>({
required String path,
String method = HttpConstant.post,
dynamic data,
Map<String, dynamic>? queryParameters,
required T Function(dynamic) fromJson,
showLoading = true,
}) async {
try {
// 🔍 打印请求信息(更详细控制)
if (kDebugMode) {
final uri = Uri.parse('${dio.options.baseUrl}$path');
final queryString = queryParameters != null ? '?${uri.queryParameters.toString()}' : '';
AppLogger.debug('🟦 API Request: $method ${uri.toString()}$queryString');
if (data != null) {
AppLogger.debug('🟦 Request Body: $data');
}
}
dioAlias.Response response;
EasyLoading.show(status: AppToastMessages.loading);
switch (method.toUpperCase()) {
case HttpConstant.get:
response = await dio.get(path, queryParameters: queryParameters);
break;
case HttpConstant.post:
response = await dio.post(path, data: data, queryParameters: queryParameters);
break;
case HttpConstant.put:
response = await dio.put(path, data: data, queryParameters: queryParameters);
break;
case HttpConstant.delete:
response = await dio.delete(path, data: data, queryParameters: queryParameters);
break;
case HttpConstant.patch:
response = await dio.patch(path, data: data, queryParameters: queryParameters);
break;
default:
return ApiResponse.error('Unsupported method: $method');
}
// ✅ 打印响应
if (kDebugMode) {
AppLogger.debug('🟩 API Response [${response.statusCode}] ${response.requestOptions.path}');
AppLogger.debug('🟩 Response Data: ${response.data}');
}
if (response.statusCode! >= 200 && response.statusCode! < 300) {
final jsonMap = response.data as Map<String, dynamic>;
// ✅ 直接用 ApiResponse.fromJson 解析整个响应
final apiResponse = ApiResponse<T>.fromJson(jsonMap, fromJson);
// ✅ 判断业务是否成功(根据 errorCode
if (apiResponse.errorCode == 0) {
return apiResponse; // 直接返回data 已解析
} else {
// 业务失败,但 data 可能有部分信息
return ApiResponse.error(
apiResponse.errorMsg ?? 'Request failed',
errorCode: apiResponse.errorCode,
data: apiResponse.data,
);
}
} else {
return ApiResponse.error(
response.statusMessage ?? 'Request failed',
errorCode: response.statusCode,
);
}
} on dioAlias.DioException catch (e) {
// ❌ 打印错误
if (kDebugMode) {
AppLogger.error('🟥 API Error: ${e.type} - ${e.message}', error: e);
if (e.response != null) {
AppLogger.error('🟥 Error Response: ${e.response?.data}');
AppLogger.error('🟥 Status Code: ${e.response?.statusCode}');
}
}
String message = 'Unknown error';
int? statusCode = e.response?.statusCode;
if (e.type == dioAlias.DioExceptionType.connectionTimeout) {
message = 'Connection timeout';
} else if (e.type == dioAlias.DioExceptionType.receiveTimeout) {
message = 'Server timeout';
} else if (e.type == dioAlias.DioExceptionType.badResponse) {
message = e.response?.statusMessage ?? 'Bad response';
} else if (e.type == dioAlias.DioExceptionType.connectionError) {
message = 'Network not available';
} else {
message = e.message ?? 'Something went wrong';
}
return ApiResponse.error(message, errorCode: statusCode);
} catch (e) {
if (kDebugMode) {
AppLogger.error('🟥 Unexpected Error: $e', error: e);
}
return ApiResponse.error('Unexpected error: $e');
} finally {
EasyLoading.dismiss();
}
}
}