Dio官方地址
pubdev地址:https://pub.dev/packages/dio 中文README:https://github.com/cfug/dio/blob/main/dio/README-ZH.md
简单使用
引入依赖
dart
dio: ^5.4.0
导入dio框架
Get请求
post请求
请求数据并渲染界面
dart
class DioPage extends StatefulWidget {
const DioPage({Key? key}) : super(key: key);
@override
State<DioPage> createState() => _DioPageState();
}
class _DioPageState extends State<DioPage> {
final Dio dio = Dio();
String? result;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("dio请求"),
),
body: SingleChildScrollView(
child: Column(
children: [
ElevatedButton(
onPressed: () => {_get()}, child: const Text("get请求")),
Text(
result ?? "无数据",
style: const TextStyle(fontSize: 12),
),
],
),
));
}
_get() async {
Response response = (await dio.get("http://www.baidu.com"));
setState(() {
result = response.data.toString();
});
}
}
封装
单例模式
首先创建单例对象,这里可以使用dart的语法糖
java
static DioInstance? _instance; //静态私有变量
DioInstance._(); //静态的私有构造方法
//实例为空则初始化
static DioInstance getInstance() {
return _instance ??= DioInstance._();
}
初始化dio,配置一些基本参数
配置请求方法为静态字符串变量 封装get和post请求,这里直接返回的是Future<Response>
java
Future<Response> get({
required String path,
Map<String, dynamic>? params,
Options? options,
CancelToken? cancelToken,
}){
return _dio.get(path,
queryParameters: params,
options: options ?? Options(
method: HttpMethod.GET,
receiveTimeout: _defaultTime,
sendTimeout: _defaultTime
),
cancelToken: cancelToken);
}
Future<Response> post({
required String path,
Object? data,
Map<String, dynamic>? params,
Options? options,
CancelToken? cancelToken,
}){
return _dio.post(path,
data: data,
queryParameters: params,
options: options ?? Options(
method: HttpMethod.POST,
receiveTimeout: _defaultTime,
sendTimeout: _defaultTime
),
cancelToken: cancelToken);
}
初始化DioInstance,在启动app时开始初始化
输出日志
上面的get和post的返回类型是Future<Response>
,但是我们展示层其实只用关心Response
对象下的data即可。 所以可以修改get和post的返回类型,直接返回Response
的data 并且添加日志输出
java
get({
required String path,
Map<String, dynamic>? params,
Options? options,
CancelToken? cancelToken,
}) async{
Response? response;
try {
response = await _dio.get(path,
queryParameters: params,
options: options ?? Options(
method: HttpMethod.GET,
receiveTimeout: _defaultTime,
sendTimeout: _defaultTime
),
cancelToken: cancelToken);
print('get success---------${response.realUri}');
print('get success---------${response.statusCode}');
print('get success---------${response.data}');
}on DioError catch(e){
print('get error---------$e');
formatError(e);
}
return response?.data;
}
post({
required String path,
Object? data,
Map<String, dynamic>? params,
Options? options,
CancelToken? cancelToken,
}) async{
Response? response;
try {
response = await _dio.post(path,
data: data,
queryParameters: params,
options: options ?? Options(
method: HttpMethod.POST,
receiveTimeout: _defaultTime,
sendTimeout: _defaultTime
),
cancelToken: cancelToken);
print('post success---------${response.realUri}');
print('post success---------${response.statusCode}');
print('post success---------${response.data}');
}on DioError catch(e){
print('post error---------$e');
formatError(e);
}
return response?.data;
}
添加拦截器
Dio通过也支持配置拦截器,那么可以添加拦截器来实现打印日志输出的功能。 除此之外还可以通过配置拦截器来统一异常处理。 实现一个打印日志输出的拦截器,继承InterceptorsWrapper方法,并实现其中的三个方法,分别代表
- 获取发起请求的信息onRequest
- 获取请求得到的信息onResponse
- 获取请求异常的信息onError
java
class PrintLogInterceptor extends InterceptorsWrapper{
//发起请求的信息
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
log("\nrequest----------->");
options.headers?.forEach((key, value) {
log("请求头信息:key=$key value=${value.toString()}");
});
log("path:${options.uri}");
log("method:${options.method}");
log("data:${options.data}");
log("queryParams:${options.queryParameters.toString()}");
log("<----------request\n");
super.onRequest(options, handler);
}
//请求得到的结果
@override
void onResponse(Response response, ResponseInterceptorHandler handler) {
log("\nresponse----------->");
log("path:${response.realUri}");
log("header:${response.headers.toString()}");
log("statusMessage:${response.statusMessage}");
log("statusCode:${response.statusCode}");
log("extra:${response.extra.toString()}");
log("data:${response.data.toString()}");
log("<----------response\n");
super.onResponse(response, handler);
}
//请求异常
@override
void onError(DioError err, ErrorInterceptorHandler handler) {
log("\nonError----------->");
log("err:${err.toString()}");
log("<----------onError\n");
super.onError(err, handler);
}
}
然后就是使用这个拦截器 重新运行可以看到控制台已经打印出信息
添加异常拦截器
因为数据返回具有一定的格式,我们可以创建一个数据基类,提前将返回的数据解析成固定的格式,然后通过判断其中的errorCode字段来提前对数据进行拦截处理,如果错误码不对,可以提前拦截数据去做相应的逻辑。 如果errorCode字段正常,则对数据进行进一步解析
java
///
/// @DIR_PATH:lib/http
/// @TIME:2024/6/6 21:00
/// @AUTHOR:starr
/// 创建数据基类,提前将返回的数据解析成固定的格式
class BaseModel<T> {
T? data;
int? errorCode;
String? errorMsg;
BaseModel.fromJson(dynamic json){
data = json['data'];
errorCode = json['errorCode'];
errorMsg = json['errorMsg'];
}
}
java
import 'package:dio/dio.dart';
import 'package:flutter_base/http/base_model.dart';
import 'package:oktoast/oktoast.dart';
///
/// @DIR_PATH:lib/http
/// @TIME:2024/6/6 21:03
/// @AUTHOR:starr
///
///
class ResponseInterceptor extends InterceptorsWrapper{
@override
void onResponse(Response response, ResponseInterceptorHandler handler) {
if(response.statusCode==200){
try{
var rsp = BaseModel.fromJson(response.data);
if(rsp.errorCode==0){
if(rsp.data==null){
//解析成功,但是没有数据
handler.next(Response(requestOptions: response.requestOptions,data: true));
}else{
//解析成功,并且有数据
handler.next(Response(requestOptions: response.requestOptions,data: rsp.data));
}
//未登录
}else if(rsp.errorCode == -1001) {
handler.reject(DioException(requestOptions: response.requestOptions,message: "未登录"));
showToast("未登录");
}else{
//未知错误
handler.reject(DioException(requestOptions: response.requestOptions,message: "未知错误"));
showToast("未知错误");
}
}catch (e){
handler.reject(DioException(requestOptions: response.requestOptions,message: "$e"));
}
}else{
handler.reject(DioException(requestOptions: response.requestOptions));
}
}
}