#dio 网络请求
dio: ^5.1.1
#https://github.com/llfbandit/dio_cache_interceptor
#dio 缓存拦截器(如果使用的话:cacheStore = MemCacheStore(maxSize: 10485760, maxEntrySize: 1048576);)
dio_cache_interceptor: ^3.4.1
#dio 文件缓存拦截器(本项目使用此插件)
dio_cache_interceptor_file_store: ^1.2.2
#dio 重试拦截器
dio_smart_retry: ^5.0.0
#dio 日志拦截器
pretty_dio_logger: ^1.3.1
#缓存需要的路径
path_provider: ^2.0.14
import 'package:dio/dio.dart';
import 'package:dio_cache_interceptor/dio_cache_interceptor.dart';
import 'package:dio_cache_interceptor_file_store/dio_cache_interceptor_file_store.dart';
import 'package:dio_smart_retry/dio_smart_retry.dart';
import 'package:pretty_dio_logger/pretty_dio_logger.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' show join;
关于 dio 拦截器:https://github.com/llfbandit/dio_cache_interceptor
/// 网路请求 Dio 工具类
class DioUtils {
late final Dio _dio;
CacheOptions? _cacheOptions;
/// 单例
static DioUtils? _instance;
factory DioUtils() => _instance ??= DioUtils._internal();
static DioUtils get shared => _instance ??= DioUtils._internal();
// 私有命名构造函数
DioUtils._internal() {
/// dio 配置
BaseOptions baseOptions = BaseOptions(
connectTimeout: const Duration(seconds: 10),
receiveTimeout: const Duration(seconds: 10),
sendTimeout: const Duration(seconds: 10),
baseUrl: 'https://gateway.ngrok.i84.com.cn/',
);
/// 初始化 dio 实例
_dio = Dio(baseOptions);
}
/// 初始化 Dio 拦截器配置
Future dioInterceptorConfig() async {
/// 一定要注意拦截器的顺序,第一个为缓存,如果缓存执行就不需要走下面的逻辑了,网络拦截器注意放在最后。
_cacheOptions = await _geFileCacheOptions();
/// 设置拦截器
_dio
// 缓存拦截器
..interceptors.add(DioCacheInterceptor(options: _cacheOptions!))
// 重试拦截器
..interceptors.add(RetryInterceptor(dio: _dio))
// 网络拦截器,发生网络请求/响应后使用
..interceptors.add(
InterceptorsWrapper(
onRequest: (request, handler) {
// 可以添加 header 信息
// request.headers["token"] = "";
handler.next(request);
},
onResponse: (response, handler) {
if (response.data == null) {
response.data["data"] = jsonDecode("{}");
}
handler.next(response);
},
onError: (e, handler) {
print("错误 error:${e.error} === ${e.message} === ${e.response?.statusCode} === ${e.type}");
},
),
)
// 日志拦截器
..interceptors.add(PrettyDioLogger(
request: true,
requestBody: true,
responseBody: true,
compact: true,
error: true,
));
}
}
/// Dio 缓存拦截器配置 options
extension DioUtilsCacheExtension on DioUtils {
Future _geFileCacheOptions() async {
/// 缓存的文件夹名称
// String cacheDirName = "system_env_info";
/// 创建缓存路径
Directory dir = await getTemporaryDirectory();
// String path = join(dir.path, cacheDirName);
String path = dir.path;
print("缓存地址:$path");
var options = CacheOptions(
store: FileCacheStore(path),
// store: MemCacheStore(maxSize: 10485760, maxEntrySize: 1048576),
policy: CachePolicy.request,
hitCacheOnErrorExcept: [401, 403],
maxStale: const Duration(days: 7),
priority: CachePriority.normal,
allowPostMethod: true,
keyBuilder: CacheOptions.defaultCacheKeyBuilder,
);
return options;
}
}
/// 请求结果做一个包装,用于识别请求结果是来自于缓存还是网络
enum HttpResultType {
success,
failure,
catchError,
}
/// 可根据自己的需求,定义最终返回的模型
class HttpsResult {
final T? data;
final String? message;
final int code;
final int statusCode;
final String? statusMessage;
final bool isCache;
final HttpResultType resultType;
final dynamic catchError;
HttpsResult({
required this.resultType,
this.data,
this.code = 0,
this.message,
this.statusCode = 0,
this.statusMessage,
this.isCache = false,
this.catchError,
});
}
/// 请求扩展
extension DioRequestExtension on DioUtils {
/// @describe POST请求
///
/// @url 请求地址
///
/// @fromJson 模型转换的命名构造函数
///
/// @params 请求参数
///
/// @useCache 是否需要缓存
///
Future> post(
String url, {
required T Function(Map) fromJson,
Map params = const {},
bool useCache = false,
}) async {
/// 封装结果
HttpsResult onCacheResult(Response response, bool isCache) {
Map resultData = response.data["data"];
int code = response.data["code"] ?? 0;
String? message = response.data["msg"];
if (response.statusCode == 200) {
return HttpsResult(
resultType: HttpResultType.success,
data: fromJson(resultData),
code: code,
message: message,
statusCode: response.statusCode ?? 0,
statusMessage: response.statusMessage,
isCache: isCache,
);
} else {
return HttpsResult(
resultType: HttpResultType.failure,
data: fromJson(resultData),
code: code,
message: message,
statusCode: response.statusCode ?? 0,
statusMessage: response.statusMessage,
isCache: isCache,
);
}
}
/// 请求
try {
/*
每次请求发生两次回调,先回调缓存的结果,再回调实际请求的结果,适用于先展示缓存数据,得到网络请求结果后再刷新页面的场景。
没有缓存时只回调网络请求的结果,网络请求失败时只回调缓存的结果。
*/
Options options = _cacheOptions!
.copyWith(
policy: useCache ? CachePolicy.refreshForceCache : CachePolicy.noCache,
)
.toOptions();
final response = await _dio.post(
url,
data: params,
options: options,
);
// 有缓存
HttpsResult result;
if (response.extra["@fromNetwork@"] == false) {
// 先试用缓存
result = onCacheResult(response, true);
// 再请求一次
final newResponse = await _dio.post(
url,
data: params,
options: _cacheOptions!.copyWith(policy: CachePolicy.noCache).toOptions(),
);
if (newResponse.statusCode != 200) {
return result;
}
return onCacheResult(newResponse, false);
} else {
// 没有缓存
return onCacheResult(response, false);
}
} catch (error) {
return HttpsResult(
resultType: HttpResultType.catchError,
catchError: error,
);
}
}
}
@override
void initState() {
/// 初始化 Dio 配置
DioUtils.shared.dioInterceptorConfig();
super.initState();
}
/// Dio请求
ElevatedButton(
onPressed: () async {
var model = await DioUtils.shared.post(
'url',
params: {},
fromJson: ServerModel.fromMap,
useCache: true,
);
print("结果:${model.data?.content} === ${model.resultType}");
},
child: Text("Dio请求 post"),
)
页面更新:2024-03-20
本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828
© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号