这玩意越写越觉得像vue,于是我就跟vue的思路一样,封装网络请求。我打算分成:
- api层,也就是接口层
- http层,也就是请求层
- dio层,也就是使用dio库
添加依赖
dependencies:
dio: ^5.0.0
Pub get
下载依赖
dio层
dio层主要是加了拦截器,对数据进行连接,上传携带令牌,响应拦截令牌,日志输出等操作
import 'package:ai_hub_demo/api/response.dart';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import '../utils/constants.dart';
class DioManager {
static final DioManager _instance = DioManager._internal();
late Dio _dio;
factory DioManager() => _instance;
DioManager._internal() {
_dio = Dio(
BaseOptions(
connectTimeout: const Duration(seconds: 15),
receiveTimeout: const Duration(seconds: 15),
sendTimeout: const Duration(seconds: 10),
baseUrl: Constants.baseUrl,
headers: {'Content-Type': 'application/json'},
),
);
// 添加拦截器
_dio.interceptors.add(
InterceptorsWrapper(
onRequest: (options, handler) {
// 请求前处理,如添加token
debugPrint('Request: ${options.method} ${options.path}');
return handler.next(options);
},
onResponse: (response, handler) {
debugPrint('Response: ${response.statusCode}');
return handler.next(response);
},
onError: (DioException e, handler) {
debugPrint('Error: ${e.message}');
return handler.next(e);
},
),
);
// 开发环境添加日志拦截器
if (kDebugMode) {
_dio.interceptors.add(
LogInterceptor(
request: true,
requestHeader: true,
requestBody: true,
responseHeader: true,
responseBody: true,
error: true,
),
);
}
}
Future<ApiResponse<T>> request<T>(String path, {
required String method,
dynamic data,
Map<String, dynamic>? queryParameters,
Options? options,
CancelToken? cancelToken,
required T Function(dynamic json) fromJsonT,
}) async {
try {
final response = await _dio.request(
path,
data: data,
queryParameters: queryParameters,
options: (options ?? Options()).copyWith(method: method),
cancelToken: cancelToken,
);
final apiResponse = ApiResponse<T>.fromJson(response.data, fromJsonT);
if (apiResponse.success) {
return apiResponse;
} else {
throw DioException(
requestOptions: response.requestOptions,
response: response,
type: DioExceptionType.badResponse,
error: apiResponse.msg,
);
}
} on DioException catch (e) {
throw _handleError(e);
}
}
Dio get dio => _dio;
DioException _handleError(DioException error) {
// 统一错误处理
if (error.response != null) {
// 服务器返回了错误响应
final statusCode = error.response?.statusCode;
final data = error.response?.data;
debugPrint('Server error: $statusCode, $data');
} else {
// 请求发送错误
debugPrint('Request error: ${error.message}');
}
return error;
}
}
http层
主要就是get
、post
、delete
、put
几个请求方法的封装了
import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart';
import 'dio_manager.dart';
class ApiClient {
final Dio _dio = DioManager().dio;
Future<Response> get(
String path, {
Map<String, dynamic>? queryParameters,
Options? options,
CancelToken? cancelToken,
}) async {
try {
final response = await _dio.get(
path,
queryParameters: queryParameters,
options: (options ?? Options()).copyWith(method: "get"),
cancelToken: cancelToken,
);
return _handleResponse(response);
} on DioException catch (e) {
throw _handleError(e);
}
}
Future<Response> put(
String path, {
Map<String, dynamic>? queryParameters,
Options? options,
CancelToken? cancelToken,
}) async {
try {
final response = await _dio.put(
path,
queryParameters: queryParameters,
options: (options ?? Options()).copyWith(method: "put"),
cancelToken: cancelToken,
);
return _handleResponse(response);
} on DioException catch (e) {
throw _handleError(e);
}
}
Future<Response> delete(
String path, {
Map<String, dynamic>? queryParameters,
Options? options,
CancelToken? cancelToken,
}) async {
try {
final response = await _dio.delete(
path,
queryParameters: queryParameters,
options: (options ?? Options()).copyWith(method: "delete"),
cancelToken: cancelToken,
);
return _handleResponse(response);
} on DioException catch (e) {
throw _handleError(e);
}
}
Future<Response> post(
String path, {
dynamic data,
Map<String, dynamic>? queryParameters,
Options? options,
CancelToken? cancelToken,
}) async {
try {
final response = await _dio.post(
path,
data: data,
queryParameters: queryParameters,
options: (options ?? Options()).copyWith(method: "post"),
cancelToken: cancelToken,
);
return _handleResponse(response);
} on DioException catch (e) {
throw _handleError(e);
}
}
Response _handleResponse(Response response) {
// 这里可以统一处理响应数据,如检查状态码等
if (response.statusCode == 200) {
return response;
} else {
throw DioException(
requestOptions: response.requestOptions,
response: response,
type: DioExceptionType.badResponse,
);
}
}
DioException _handleError(DioException error) {
// 统一错误处理
if (error.response != null) {
// 服务器返回了错误响应
final statusCode = error.response?.statusCode;
final data = error.response?.data;
debugPrint('Server error: $statusCode, $data');
} else {
// 请求发送错误
debugPrint('Request error: ${error.message}');
}
return error;
}
}
接口层封装
接口层就是api了
import 'package:ai_hub_demo/api/http_dio.dart';
import 'package:ai_hub_demo/api/response.dart';
import 'package:ai_hub_demo/model/login_ao.dart';
import 'package:flutter/cupertino.dart';
class AiHubApi {
static final AiHubApi _instance = AiHubApi._internal();
factory AiHubApi() => _instance;
AiHubApi._internal() {}
final ApiClient _apiClient = ApiClient();
Future<ApiResponse<Null>> login(LoginAo loginAo) async {
return _apiClient.post("/uc/sign_in", data: loginAo).then((value) {
debugPrint("rest => $value");
return value.data;
});
}
}
以上,我只做了一个登录的封装
其他的封装可以继续加,封装好后,就调用。
这里的调用跟vue的promise思想差不多。要么你await同步等待,要么你异步回调处理结果。