dio是一个非常强大的网络请求库,可以支持发送各种网络请求,就像axios一样灵活强大,但是官网没有做一个demo示例,所以前端同学使用起来还是有点费劲,所以就想在这里封装一下,方便前端同学使用。
官网地址:dio | Dart Package
我的flutter模板项目地址: GitHub - Sjj1024/flutter_windows: 使用flutter开发跨平台桌面软件的案例
添加依赖
在pubspec.yaml文件中添加所需要的第三方依赖库
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2
get: ^4.6.6
dio: ^5.4.0
封装基础请求工具
在utils里面新建一个request.dart文件,专门用来做请求工具的,就像前端框架里面集成axios一样:统一初始化网络请求常见配置,实现请求拦截器、响应拦截器以及错误处理。
request.dart 代码:
import 'package:dio/dio.dart';
/// 请求方法:枚举类型
enum DioMethod {
get,
post,
put,
delete,
patch,
head,
}
// 创建请求类:封装dio
class Request {
/// 单例模式
static Request? _instance;
// 工厂函数:执行初始化
factory Request() => _instance ?? Request._internal();
// 获取实例对象时,如果有实例对象就返回,没有就初始化
static Request? get instance => _instance ?? Request._internal();
/// Dio实例
static Dio _dio = Dio();
/// 初始化
Request._internal() {
// 初始化基本选项
BaseOptions options = BaseOptions(
baseUrl: 'http://你的服务器地址',
connectTimeout: const Duration(seconds: 5),
receiveTimeout: const Duration(seconds: 5));
_instance = this;
// 初始化dio
_dio = Dio(options);
// 添加拦截器
_dio.interceptors.add(InterceptorsWrapper(
onRequest: _onRequest, onResponse: _onResponse, onError: _onError));
}
/// 请求拦截器
void _onRequest(RequestOptions options, RequestInterceptorHandler handler) {
// 对非open的接口的请求参数全部增加userId
if (!options.path.contains("open")) {
options.queryParameters["userId"] = "xxx";
}
// 头部添加token
// options.headers["token"] = "xxx";
// 更多业务需求
handler.next(options);
// super.onRequest(options, handler);
}
/// 相应拦截器
void _onResponse(
Response response, ResponseInterceptorHandler handler) async {
// 请求成功是对数据做基本处理
if (response.statusCode == 200) {
// 处理成功的响应
// print("响应结果: $response");
} else {
// 处理异常结果
print("响应异常: $response");
}
handler.next(response);
}
/// 错误处理: 网络错误等
void _onError(DioException error, ErrorInterceptorHandler handler) {
handler.next(error);
}
/// 请求类:支持异步请求操作
Future<T> request<T>(
String path, {
DioMethod method = DioMethod.get,
Map<String, dynamic>? params,
dynamic data,
CancelToken? cancelToken,
Options? options,
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
const _methodValues = {
DioMethod.get: 'get',
DioMethod.post: 'post',
DioMethod.put: 'put',
DioMethod.delete: 'delete',
DioMethod.patch: 'patch',
DioMethod.head: 'head'
};
// 默认配置选项
options ??= Options(method: _methodValues[method]);
try {
Response response;
// 开始发送请求
response = await _dio.request(path,
data: data,
queryParameters: params,
cancelToken: cancelToken,
options: options,
onSendProgress: onSendProgress,
onReceiveProgress: onReceiveProgress);
return response.data;
} on DioException catch (e) {
print("发送请求异常: $e");
rethrow;
}
}
/// 开启日志打印
/// 需要打印日志的接口在接口请求前 Request.instance?.openLog();
void openLog() {
_dio.interceptors
.add(LogInterceptor(responseHeader: false, responseBody: true));
}
}
管理apis网络请求
然后创建一个apis文件夹,集成所有的apis网络请求,并在里面创建user.dart、goods.dart等文件,用于对不同的网络请求进行管理,这样就可以知道我们相关的网路请求放在哪里面。并且对返回的数据根据实际需求进行处理,如果数据的修改需要更新UI或者需要全局共享该数据
app.dart文件代码:
import '../utils/request.dart';
// 创建一个关于user相关请求的对象
class UserApi {
/// 单例模式
static UserApi? _instance;
// 工厂函数:初始化,默认会返回唯一的实例
factory UserApi() => _instance ?? UserApi._internal();
// 用户Api实例:当访问UserApi的时候,就相当于使用了get方法来获取实例对象,如果_instance存在就返回_instance,不存在就初始化
static UserApi? get instance => _instance ?? UserApi._internal();
/// 初始化
UserApi._internal() {
// 初始化基本选项
}
/// 获取权限列表
getUser() async {
/// 开启日志打印
Request.instance?.openLog();
/// 发起网络接口请求
var result = await Request().request('get_user', method: DioMethod.get);
// 返回数据
return result.data;
}
// 获取列表数据
getGoods() async {
var result = await Request().request("/game/gamemgnt",
method: DioMethod.post,
data: {"taskuuid": "queryprod", "splist": "66"});
// 返回数据
// print("getDetail:$result");
return result;
}
// 获取列表数据
getDetail() async {
var result = await Request().request("/game/gamemgnt",
method: DioMethod.post,
data: {"taskuuid": "queryprod", "splist": "66"});
// 返回数据
// print("getDetail:$result");
return result;
}
}
// 导出全局使用这一个实例
final userApi = UserApi();
在组件页面使用
然后就可以到组件页面导入userApi给组件页面上使用,发送相应的网络请求了:
页面组件导入并发送请求获取数据,然后渲染:
import 'package:flutter/material.dart';
import 'package:flutter_windows/apis/app.dart';
class Lists extends StatefulWidget {
const Lists({super.key});
@override
State<Lists> createState() => _ListsState();
}
class _ListsState extends State<Lists> {
// 列表数据
List goods = [];
@override
void initState() {
// TODO: implement initState
super.initState();
// 获取商品列表
getGoods();
}
// 获取列表
getGoods() async {
var res = await userApi.getGoods();
var goodsData = res['response_data']['data'];
setState(() {
goods = goodsData;
});
}
// 动态列表组件
List<Widget> _getListData() {
var tempList = goods.map((value) {
return Container(
decoration: BoxDecoration(
border: Border.all(
color: const Color.fromRGBO(233, 233, 233, 0.9), width: 1)),
child: Column(
children: <Widget>[
Image.network(
value['skillurl'],
width: 100,
height: 200,
),
const SizedBox(height: 12),
Text(
value['pordname'],
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 20),
)
],
),
);
}); // ('xxx','xxx')
print("渲染的列表组件类型:${tempList.toList().runtimeType}");
return tempList.toList();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("产品列表"),
),
body: GridView.count(
crossAxisSpacing: 10.0,
//水平子 Widget 之间间距
mainAxisSpacing: 10.0,
//垂直子 Widget 之间间距
padding: const EdgeInsets.all(2),
crossAxisCount: 4,
//一行的 Widget 数量
// childAspectRatio: 0.7,
//宽度和高度的比例
children: goods.map((value) {
return Container(
decoration: BoxDecoration(
border: Border.all(
color: const Color.fromRGBO(233, 233, 233, 0.9), width: 1)),
child: Column(
children: <Widget>[
Image.network(
value['skillurl'],
width: 100,
height: 200,
),
const SizedBox(height: 12),
Text(
value['pordname'],
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 20),
)
],
),
);
}).toList(),
),
);
}
}
最后展示的效果: