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.2get: ^4.6.6dio: ^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的接口的请求参数全部增加userIdif (!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});@overrideState<Lists> createState() => _ListsState();
}class _ListsState extends State<Lists> {// 列表数据List goods = [];@overridevoid initState() {// TODO: implement initStatesuper.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();}@overrideWidget 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(),),);}
}
最后展示的效果: