文章目录
- 效果
- 使用
- ResponseEntity类
- DioManager封装
- _onResponse / _onDioException 的设计
- Response的处理
- catch处理
效果
请求成功/失败/异常的日志输出效果
成功:
失败:500
失败:404
网络异常:
使用
举个使用的例子, 在调用 DioManager
的时候, 直接通过返回值的状态, 来处理各个情况,不用在 try{}catch{}里面各写一遍处理逻辑,
比如上图,就是直接调用的封装的API
ResponseEntity res = await DioManager().requestGet(HttpApi.user_record, param: {
"openid": "okqbz5K-4UoymmukFtxyQAyImKm0",
"uid": "88030",
"subject": '20',
"unionid": "ofJJv6M45ChFhuUZyVaLXwt07M4g",
});
res.toLog();
直接同步获取了请求的结果,通过 ResponseEntity 来处理本次请求的各项情况(如上4图)
ResponseEntity类
提供了 泛型T的data属性,
提供了 tag, 用于处理请求的不同情况
提供了 toString/ toLog函数 , 用于查看请求/返回/状态码/请求参数等
class ResponseEntity<T> {
/// 常规的response.data的返回字段
late String? msg;
late int? code;
T? data;
/// response.data中,自定以追加的一些字段(方便日志查看)
late int? tag; // 业务tag 0=>通信OK+业务未跑通 1=>通信OK+业务跑通 2=>通信失败(各类原因...) 9=>解析/socket等异常
late String? method; // 请求的 method
late String? baseUrl; // 请求的host地址 - 方便打印日子产看环境
late String? path; // 请求地址
late String? desc; // 自定义的报文描述-便于判断请求情况
late Map<String, dynamic>? queryParameters; // 请求的参数
ResponseEntity(
this.code, this.msg, this.data, this.tag, this.method, this.baseUrl, this.path, this.desc, this.queryParameters);
ResponseEntity.initFromJson(Map<String, dynamic> jsonMap) {
code = jsonMap.containsKey(ConstantUtil.code) ? jsonMap[ConstantUtil.code] as int? : 0;
msg = jsonMap.containsKey(ConstantUtil.msg) ? jsonMap[ConstantUtil.msg] as String? : "";
// 存在data
if (jsonMap.containsKey(ConstantUtil.data)) {
data = jsonMap[ConstantUtil.data] as T;
}
/// response自定以追加的一些字段处理
tag = jsonMap.containsKey(ConstantUtil.tag) ? jsonMap[ConstantUtil.tag] : 9;
method = jsonMap.containsKey(ConstantUtil.method) ? jsonMap[ConstantUtil.method] : "";
baseUrl = jsonMap.containsKey(ConstantUtil.baseUrl) ? jsonMap[ConstantUtil.baseUrl] : "";
path = jsonMap.containsKey(ConstantUtil.path) ? jsonMap[ConstantUtil.path] : "";
queryParameters = jsonMap.containsKey(ConstantUtil.queryParameters) ? jsonMap[ConstantUtil.queryParameters] : null;
desc = jsonMap.containsKey(ConstantUtil.desc) ? jsonMap[ConstantUtil.desc] : "";
}
/// 手动重写toString 方法,方便查看日志
String toString() {
var _code = "code:$code\n";
var _msg = "msg:$msg\n";
var _data = json.encode(data).toString();
var _dataString = "data:$_data\n";
var _tag = "tag:$tag\n";
var _method = "method:$method\n";
var _baseUrl = "baseUrl:$baseUrl\n";
var _path = "path:$path\n";
var _desc = "path:$desc\n";
var _queryParameters = jsonEncode(queryParameters);
var _queryParametersString = "queryParameters:$_queryParameters\n";
return _code + _msg + _dataString + _tag + _method + _baseUrl + _path + _desc + _queryParametersString;
}
/// 提供自带的打印函数
void toLog() {
LoggerUtil().d(toString());
}
}
DioManager封装
对DioManager进行单例模式处理
/// dio管理类的单例的实现 --------------------------------------------------
// 定义私有管理对象 _singleton
static final DioManager _singleton = DioManager._();
// 私有对象构造实现
DioManager._() {
// dio初始化 - 配置全局options - 具体事项先省略
}
// 声明并完成初始化的私有变量(_singleton),
// 通过 DioManager的工厂函数(factory关键字) ,进行单例模式返回
factory DioManager() => _singleton;
提供_request通用方法
/// request 通用处理函数 -----------------------------------------------------------
/// get 对应的是 queryParam
/// post 对应的是 data
/// 通过 对 try/catch 的处理, 均异步返回有效的 BaseResponseEntity<T> 实例,
/// 外部调用时候,仅获取数据是, 可以不必包裹 try/catch,
Future<ResponseEntity<T>> _request<T>(
String method,
String apiPath, {
Map<String, dynamic>? param,
CancelToken? cancelToken,
Options? options,
}) async {
try {
// 通用请求
Response<dynamic> response = await _dio.request(apiPath,
data: param, queryParameters: param, cancelToken: cancelToken, options: _loadOptions(method, options));
// 通过 _onResponse()函数转换response
// 自定义返回的data内容, 除了原有的 code/msg/data信息, 新增desc/tag等返回数据
response = _onResponse(response);
return ResponseEntity<T>.initFromJson(response.data);
} on DioException catch (err) {
// 通过对DioException的解析,返回自定义的BaseResponseEntity实例
return _onDioException(err) as ResponseEntity<T>;
}
}
_onResponse / _onDioException 的设计
根据Request的情况, 把交互场景分为了四类
1&2: statusCode == 200 , 再区分业务code是否OK
3: statusCode !==200, 可能是 404 /500 等情况
4: 断网等异常情况
其中 1&2&3, 都是通过_onResponse
处理
4通过_onDioException
处理, 这里的catch不再直接抛出, 用ResponseEntity来统一做返回格式处理
(DioException)
Response的处理
class ResponseEntity<T> {
/// 常规的response.data的返回字段
late String? msg;
late int? code;
T? data;
/// response.data中,自定以追加的一些字段(方便日志查看)
late int? tag; // 业务tag 0=>通信OK+业务未跑通 1=>通信OK+业务跑通 2=>通信失败(各类原因...) 9=>解析/socket等异常
late String? method; // 请求的 method
late String? baseUrl; // 请求的host地址 - 方便打印日子产看环境
late String? path; // 请求地址
late String? desc; // 自定义的报文描述-便于判断请求情况
late Map<String, dynamic>? queryParameters; // 请求的参数
ResponseEntity(
this.code, this.msg, this.data, this.tag, this.method, this.baseUrl, this.path, this.desc, this.queryParameters);
ResponseEntity.initFromJson(Map<String, dynamic> jsonMap) {
code = jsonMap.containsKey(ConstantUtil.code) ? jsonMap[ConstantUtil.code] as int? : 0;
msg = jsonMap.containsKey(ConstantUtil.msg) ? jsonMap[ConstantUtil.msg] as String? : "";
// 存在data
if (jsonMap.containsKey(ConstantUtil.data)) {
data = jsonMap[ConstantUtil.data] as T;
}
/// response自定以追加的一些字段处理
tag = jsonMap.containsKey(ConstantUtil.tag) ? jsonMap[ConstantUtil.tag] : 9;
method = jsonMap.containsKey(ConstantUtil.method) ? jsonMap[ConstantUtil.method] : "";
baseUrl = jsonMap.containsKey(ConstantUtil.baseUrl) ? jsonMap[ConstantUtil.baseUrl] : "";
path = jsonMap.containsKey(ConstantUtil.path) ? jsonMap[ConstantUtil.path] : "";
queryParameters = jsonMap.containsKey(ConstantUtil.queryParameters) ? jsonMap[ConstantUtil.queryParameters] : null;
desc = jsonMap.containsKey(ConstantUtil.desc) ? jsonMap[ConstantUtil.desc] : "";
}
/// 手动重写toString 方法,方便查看日志
String toString() {
var _code = "code:$code\n";
var _msg = "msg:$msg\n";
var _data = json.encode(data).toString();
var _dataString = "data:$_data\n";
var _tag = "tag:$tag\n";
var _method = "method:$method\n";
var _baseUrl = "baseUrl:$baseUrl\n";
var _path = "path:$path\n";
var _desc = "path:$desc\n";
var _queryParameters = jsonEncode(queryParameters);
var _queryParametersString = "queryParameters:$_queryParameters\n";
return _code + _msg + _dataString + _tag + _method + _baseUrl + _path + _desc + _queryParametersString;
}
/// 提供自带的打印函数
void toLog() {
LoggerUtil().d(toString());
}
}
catch处理
/// 对 DioException进行解析,基本覆盖大部分错误类型了
ResponseEntity _onDioException(DioException err) {
var errType = err.type;
var path = err.requestOptions.path;
var data = err.requestOptions.data;
var queryParameters = err.requestOptions.queryParameters;
var baseUrl = err.requestOptions.baseUrl;
var method = err.requestOptions.method;
ResponseEntity baseResponseEntity = ResponseEntity(0, "", data, 9, method, baseUrl, path, "", queryParameters);
///连接超时
if (errType == DioExceptionType.connectionTimeout) {
baseResponseEntity.msg = "连接超时";
baseResponseEntity.desc = "连接超时";
}
///发送超时
if (errType == DioExceptionType.sendTimeout) {
baseResponseEntity.msg = "发送超时";
baseResponseEntity.desc = "发送超时";
}
///接收超时
if (errType == DioExceptionType.receiveTimeout) {
baseResponseEntity.msg = "接收超时";
baseResponseEntity.desc = "接收超时";
}
///证书损坏
if (errType == DioExceptionType.badCertificate) {
baseResponseEntity.msg = "证书损坏";
baseResponseEntity.desc = "证书损坏";
}
///返回内容问题
if (errType == DioExceptionType.badResponse) {
baseResponseEntity.msg = "返回内容问题";
baseResponseEntity.desc = "返回内容问题";
}
///请求取消
if (errType == DioExceptionType.cancel) {
baseResponseEntity.msg = "请求取消";
baseResponseEntity.desc = "请求取消";
}
///连接错误-无网络
if (errType == DioExceptionType.connectionError) {
baseResponseEntity.msg = "连接错误-无网络";
baseResponseEntity.desc = "连接错误-无网络";
}
///未知错误
if (errType == DioExceptionType.unknown) {
baseResponseEntity.msg = "未知错误";
baseResponseEntity.desc = "未知错误";
}
return baseResponseEntity;
}
针对ResponseEntity中, T? data 的处理, 稍后补上, 先走通请求…
— 数据转模型看这个
[Flutter3] Json转dart模型举例
对于泛型T的处理, 直接把 json转model的model类型传入泛型就可获取数据