北京市建设工程交易服务中心网站做网站找那个公司

张小明 2025/12/28 18:00:44
北京市建设工程交易服务中心网站,做网站找那个公司,服务器网站建设流程图,广告设计公司员工荣誉证书Flutter 网络请求完全指南#xff1a;Dio 封装与拦截器实战 在 Flutter 开发中#xff0c;网络请求是连接前端与后端服务的核心桥梁#xff0c;直接影响应用的交互体验与数据流转效率。Dio 作为 Flutter 生态中最主流的网络请求库#xff0c;支持 RESTful API、FormData、…Flutter 网络请求完全指南Dio 封装与拦截器实战在 Flutter 开发中网络请求是连接前端与后端服务的核心桥梁直接影响应用的交互体验与数据流转效率。Dio 作为 Flutter 生态中最主流的网络请求库支持 RESTful API、FormData、拦截器、请求取消、超时设置等丰富功能几乎能满足所有网络请求场景需求。本文将从 Dio 基础用法入手逐步深入到企业级封装方案、拦截器实战技巧再到异常处理、请求取消等高级用法为开发者提供一份全面的 Dio 实战指南。作者爱吃大芒果个人主页 爱吃大芒果本文所属专栏 Flutter更多专栏Ascend C 算子开发教程进阶鸿蒙集成从0到1自学C一、Dio 基础快速上手与核心配置在进行复杂封装前首先需要掌握 Dio 的基础用法与核心配置快速实现简单的 GET/POST 请求。1. 环境准备添加依赖与权限首先在pubspec.yaml中添加 Dio 依赖推荐使用最新稳定版可在 pub.dev 查看最新版本dependencies:flutter:sdk:flutterdio:^5.4.3# 最新稳定版json_annotation:^4.8.1# 可选用于 JSON 序列化推荐配套使用flutter_dotenv:^5.1.0# 可选用于管理环境变量如 baseUrl针对 Android 平台需在android/app/src/main/AndroidManifest.xml中添加网络权限uses-permissionandroid:nameandroid.permission.INTERNET/针对 iOS 平台需在ios/Runner/Info.plist中添加以下配置iOS 10 要求keyNSAppTransportSecurity/keydictkeyNSAllowsArbitraryLoads/keytrue//dict注意生产环境中不建议直接开启NSAllowsArbitraryLoads应针对性配置NSExceptionDomains允许指定域名的 HTTP 访问或直接使用 HTTPS。2. 核心配置Dio 实例初始化Dio 支持通过构造函数或options属性配置全局参数核心配置项包括baseUrl基础请求地址避免重复拼接 URLconnectTimeout连接超时时间默认 5 秒receiveTimeout接收超时时间默认 30 秒headers全局请求头如 Token、Content-TyperesponseType响应数据类型默认ResponseType.json。基础初始化示例importpackage:dio/dio.dart;// 初始化 Dio 实例finalDio dioDio()..optionsBaseOptions(baseUrl:https://api.example.com/v1,// 基础地址connectTimeout:constDuration(seconds:5),// 连接超时receiveTimeout:constDuration(seconds:30),// 接收超时headers:{Content-Type:application/json,User-Agent:Flutter-Dio-Client,},responseType:ResponseType.json,);3. 基础请求GET 与 POST 实现Dio 对 GET/POST 等常用请求提供了简洁的 API支持异步调用使用async/await。1GET 请求查询参数传递GET 请求通过queryParameters参数传递查询参数适用于数据查询场景// 发起 GET 请求获取用户列表FutureListUsergetUserList({int page1,int size20})async{try{finalresponseawaitdio.get(/users,// 接口路径拼接 baseUrl 后为 https://api.example.com/v1/usersqueryParameters:{page:page,size:size},// 查询参数);// 解析响应数据假设后端返回格式为 { code: 200, data: [...], msg: success }if(response.data[code]200){return(response.data[data]asList).map((json)User.fromJson(json)).toList();}else{throwException(获取用户列表失败${response.data[msg]});}}catch(e){throwException(请求异常$e);}}2POST 请求JSON 与 FormData 提交POST 请求适用于数据提交场景支持 JSON 格式与 FormData 格式文件上传常用// 1. JSON 格式提交用户登录FutureLoginResponselogin({required String username,required String password})async{try{finalresponseawaitdio.post(/login,data:{username:username,password:password},// JSON 数据);if(response.data[code]200){returnLoginResponse.fromJson(response.data[data]);}else{throwException(登录失败${response.data[msg]});}}catch(e){throwException(登录异常$e);}}// 2. FormData 格式提交文件上传FutureStringuploadFile({required String filePath})async{try{finalformDataFormData.fromMap({file:awaitMultipartFile.fromFile(filePath,filename:filePath.split(/).last,// 文件名),type:avatar,// 额外参数});finalresponseawaitdio.post(/upload,data:formData,options:Options(headers:{Content-Type:multipart/form-data},// 自动设置可省略),);if(response.data[code]200){returnresponse.data[data][fileUrl];// 返回文件 URL}else{throwException(文件上传失败${response.data[msg]});}}catch(e){throwException(上传异常$e);}}二、企业级封装高内聚低耦合的 Dio 工具类基础用法虽简洁但在大型项目中存在代码冗余、维护困难等问题。通过封装 Dio 工具类可实现请求统一管理、全局配置复用、异常集中处理提升代码可维护性。1. 封装思路分层设计与单一职责采用“工具类 接口层 模型层”的分层设计工具类DioUtil封装 Dio 实例、全局配置、拦截器、请求方法get/post/upload 等接口层ApiService集中管理所有接口地址与请求参数避免硬编码模型层Model通过 JSON 序列化工具生成数据模型统一解析响应数据。2. 完整封装实现DioUtil 工具类importpackage:dio/dio.dart;importpackage:flutter_dotenv/flutter_dotenv.dart;// 网络请求工具类classDioUtil{// 单例模式懒加载staticfinalDioUtil _instanceDioUtil._internal();factoryDioUtil()_instance;late Dio _dio;// 私有构造函数初始化 Dio 配置DioUtil._internal(){_dioDio()..optionsBaseOptions(baseUrl:dotenv.env[BASE_URL]??https://api.example.com/v1,// 从环境变量读取 baseUrlconnectTimeout:constDuration(seconds:5),receiveTimeout:constDuration(seconds:30),headers:{Content-Type:application/json},);// 添加拦截器后续详解_addInterceptors();}// 添加拦截器void_addInterceptors(){// 请求拦截器添加 Token、日志打印等_dio.interceptors.add(InterceptorsWrapper(onRequest:(options,handler){// 示例添加 Token从本地缓存获取finalString?token_getLocalToken();if(token!null){options.headers[Authorization]Bearer $token;}print(请求信息${options.method} ${options.uri}参数${options.data});returnhandler.next(options);// 继续请求},onResponse:(response,handler){print(响应信息${response.statusCode}数据${response.data});returnhandler.next(response);// 继续处理响应},onError:(DioException e,handler){print(请求异常${e.message});returnhandler.next(e);// 继续处理异常},),);// 日志拦截器可选用于调试_dio.interceptors.add(LogInterceptor(responseBody:true));}// 从本地缓存获取 Token示例方法实际需结合本地存储库如 shared_preferencesString?_getLocalToken(){// 实际场景return await SharedPreferences.getInstance().then((prefs) prefs.getString(token));returntest_token_123456;}// 通用 GET 请求FutureTgetT(String path,{MapString,dynamic?queryParameters,Options?options,})async{try{finalresponseawait_dio.get(path,queryParameters:queryParameters,options:options,);return_handleResponseT(response);}onDioExceptioncatch(e){_handleDioError(e);rethrow;// 抛出异常让业务层处理}}// 通用 POST 请求FutureTpostT(String path,{dynamicdata,MapString,dynamic?queryParameters,Options?options,})async{try{finalresponseawait_dio.post(path,data:data,queryParameters:queryParameters,options:options,);return_handleResponseT(response);}onDioExceptioncatch(e){_handleDioError(e);rethrow;}}// 通用文件上传请求FutureTuploadT(String path,{required FormData formData,Options?options,})async{try{finalresponseawait_dio.post(path,data:formData,options:options??Options(headers:{Content-Type:multipart/form-data},),);return_handleResponseT(response);}onDioExceptioncatch(e){_handleDioError(e);rethrow;}}// 响应处理统一解析后端返回格式T _handleResponseT(Response response){finalMapString,dynamicdataresponse.data;// 假设后端统一返回格式{ code: int, data: T, msg: String }if(data[code]200){returndata[data]asT;}else{throwException(业务异常${data[msg] ?? 未知错误});}}// Dio 异常处理分类处理超时、网络错误、404/500 等void_handleDioError(DioException e){switch(e.type){caseDioExceptionType.connectionTimeout:throwException(连接超时请检查网络);caseDioExceptionType.receiveTimeout:throwException(接收超时服务器响应缓慢);caseDioExceptionType.connectionError:throwException(网络错误请检查网络连接);caseDioExceptionType.notFound:throwException(接口不存在404);caseDioExceptionType.badResponse:throwException(服务器错误${e.response?.statusCode});default:throwException(请求失败${e.message});}}// 取消请求需配合 CancelToken 使用voidcancelRequest(CancelToken cancelToken){cancelToken.cancel(请求已取消);}}3. 接口层与模型层配合使用1接口层ApiService集中管理接口importpackage:json_annotation/json_annotation.dart;importdio_util.dart;// 接口地址常量classApiPath{staticconstString login/login;staticconstString getUserList/users;staticconstString uploadFile/upload;}// 接口服务类classApiService{staticfinalDioUtil _dioDioUtil();// 登录接口staticFutureLoginResponselogin({required String username,required String password})async{finaldataawait_dio.postMapString,dynamic(ApiPath.login,data:{username:username,password:password},);returnLoginResponse.fromJson(data);}// 获取用户列表接口staticFutureListUsergetUserList({int page1,int size20})async{finaldataawait_dio.getListdynamic(ApiPath.getUserList,queryParameters:{page:page,size:size},);returndata.map((json)User.fromJson(json)).toList();}// 文件上传接口staticFutureUploadResponseuploadAvatar({required String filePath})async{finalformDataFormData.fromMap({file:awaitMultipartFile.fromFile(filePath,filename:filePath.split(/).last),type:avatar,});finaldataawait_dio.uploadMapString,dynamic(ApiPath.uploadFile,formData:formData,);returnUploadResponse.fromJson(data);}}2模型层通过 json_serializable 生成首先创建模型类如login_response.dart并通过注解定义序列化规则importpackage:json_annotation/json_annotation.dart;partlogin_response.g.dart;// 生成的代码文件JsonSerializable()classLoginResponse{finalString token;finalString username;finalString avatar;LoginResponse({requiredthis.token,requiredthis.username,requiredthis.avatar,});// 从 JSON 解析模型factoryLoginResponse.fromJson(MapString,dynamicjson)_$LoginResponseFromJson(json);// 模型转换为 JSONMapString,dynamictoJson()_$LoginResponseToJson(this);}执行以下命令生成序列化代码flutter pub run build_runner build三、拦截器实战请求/响应增强与异常拦截Dio 拦截器是其核心特性之一支持在请求发起前、响应返回后、异常发生时插入自定义逻辑实现 Token 自动添加、日志打印、刷新 Token、缓存处理等功能。1. 拦截器核心原理Dio 拦截器基于“责任链模式”设计支持添加多个拦截器按添加顺序执行请求拦截器onRequest在请求发起前执行可修改请求参数如添加 Token、动态修改 baseUrl响应拦截器onResponse在响应返回后执行可统一解析响应数据、处理缓存异常拦截器onError在请求异常时执行可统一处理错误如 Token 过期刷新、网络错误提示。2. 实战场景 1Token 自动添加与过期刷新在请求拦截器中自动添加 Token在异常拦截器中处理 Token 过期401 错误并刷新 Token 后重试请求void_addInterceptors(){_dio.interceptors.add(InterceptorsWrapper(onRequest:(options,handler)async{// 1. 添加 TokenfinalString?tokenawait_getLocalToken();if(token!null){options.headers[Authorization]Bearer $token;}handler.next(options);},onError:(DioException e,handler)async{// 2. 处理 Token 过期401 错误if(e.response?.statusCode401){// 2.1 锁定拦截器避免并发请求重复刷新 Token_dio.lock();try{// 2.2 调用刷新 Token 接口finalString newTokenawait_refreshToken();if(newToken.isNotEmpty){// 2.3 保存新 Token 到本地await_saveLocalToken(newToken);// 2.4 重新设置请求头中的 Tokene.requestOptions.headers[Authorization]Bearer $newToken;// 2.5 重试原请求finalResponse responseawait_dio.fetch(e.requestOptions);returnhandler.resolve(response);// 重试成功返回新响应}}catch(refreshError){// 2.6 刷新 Token 失败跳转登录页_navigateToLogin();}finally{// 2.7 解锁拦截器_dio.unlock();}}handler.next(e);// 继续处理其他错误},),);}// 刷新 Token 接口实际需对接后端FutureString_refreshToken()async{finalresponseawait_dio.post(/refreshToken,data:{refreshToken:await_getLocalRefreshToken()},);if(response.data[code]200){returnresponse.data[data][token];}else{throwException(刷新 Token 失败);}}3. 实战场景 2请求缓存拦截器通过拦截器实现 GET 请求缓存减少重复网络请求提升离线体验需配合本地存储库如hive或shared_preferencesimportpackage:hive/hive.dart;// 缓存拦截器classCacheInterceptorextendsInterceptor{finalBox _cacheBoxHive.box(network_cache);// 初始化 Hive 缓存箱overridevoidonRequest(RequestOptions options,RequestHandler handler){// 仅对 GET 请求启用缓存if(options.methodGET){finalString cacheKey_generateCacheKey(options);finaldynamiccacheData_cacheBox.get(cacheKey);// 缓存存在且未过期直接返回缓存数据if(cacheData!null!_isCacheExpired(cacheData[timestamp])){returnhandler.resolve(Response(requestOptions:options,statusCode:200,data:cacheData[data],),);}}handler.next(options);}overridevoidonResponse(Response response,ResponseHandler handler){// 对 GET 请求结果进行缓存if(response.requestOptions.methodGET){finalString cacheKey_generateCacheKey(response.requestOptions);_cacheBox.put(cacheKey,{data:response.data,timestamp:DateTime.now().millisecondsSinceEpoch,// 缓存时间戳},);}handler.next(response);}// 生成缓存 Key基于 URL 查询参数String_generateCacheKey(RequestOptions options){return${options.uri.toString()}?${options.queryParameters.toString()};}// 判断缓存是否过期假设缓存有效期为 5 分钟bool_isCacheExpired(int timestamp){constint cacheDuration5*60*1000;// 5 分钟毫秒returnDateTime.now().millisecondsSinceEpoch-timestampcacheDuration;}}添加缓存拦截器到 Dio 实例_dio.interceptors.add(CacheInterceptor());4. 实战场景 3日志拦截器与调试优化Dio 内置LogInterceptor可快速打印请求/响应日志便于调试_dio.interceptors.add(LogInterceptor(request:true,// 打印请求信息requestHeader:true,// 打印请求头requestBody:true,// 打印请求体POST 数据responseHeader:true,// 打印响应头responseBody:true,// 打印响应体敏感数据需注意屏蔽error:true,// 打印异常信息logPrint:(object){// 自定义日志打印方式如写入文件、上传到服务器print(Dio Log: $object);},),);四、高级用法请求取消、超时设置与并发控制在复杂场景如列表下拉刷新、页面销毁时需要对请求进行精细化控制避免无效请求导致的性能问题或数据错乱。1. 请求取消CancelToken 用法Dio 支持通过CancelToken取消单个或多个请求适用于“页面销毁时取消未完成请求”“快速切换标签时取消前一个请求”等场景// 1. 创建 CancelToken 实例finalCancelToken _cancelTokenCancelToken();// 2. 发起请求时关联 CancelTokenFutureListUsergetUserList()async{try{returnawaitApiService.getUserList(cancelToken:_cancelToken,// 关联取消令牌);}onDioExceptioncatch(e){if(CancelToken.isCancel(e)){print(请求已取消${e.message});}else{throwe;}}}// 3. 取消请求如页面销毁时overridevoiddispose(){_cancelToken.cancel(页面已销毁取消请求);// 取消请求并添加原因super.dispose();}2. 超时设置全局与局部结合Dio 支持全局超时设置初始化时配置与局部超时设置单个请求单独配置局部配置会覆盖全局配置// 1. 全局超时已在 DioUtil 初始化时配置// connectTimeout: Duration(seconds: 5),// receiveTimeout: Duration(seconds: 30),// 2. 局部超时单个请求单独设置适用于大文件上传/下载FutureStringdownloadFile({required String url,required String savePath})async{finalresponseawaitDioUtil().dio.download(url,savePath,options:Options(sendTimeout:constDuration(minutes:5),// 发送超时大文件上传receiveTimeout:constDuration(minutes:5),// 接收超时大文件下载),);returnsavePath;}3. 并发控制限制同时请求数量在“批量上传文件”“同时发起多个接口请求”等场景过多并发请求可能导致网络阻塞可通过dio-queue等第三方库实现并发控制// 添加依赖dependencies:dio_queue:^1.0.0// 初始化队列拦截器限制最大并发数为 3finalQueueInterceptor queueInterceptorQueueInterceptor(maxConcurrentRequests:3,// 最大并发请求数);// 添加到 Dio 拦截器DioUtil().dio.interceptors.add(queueInterceptor);五、异常处理全面覆盖网络与业务错误网络请求过程中可能出现多种异常如网络错误、超时、404、500、业务错误等需通过统一的异常处理机制提升用户体验。1. 异常分类与处理思路将异常分为三类分别处理网络异常无网络、连接超时、接收超时等提示用户“检查网络连接”HTTP 异常404接口不存在、500服务器错误、401未授权等根据状态码给出对应提示业务异常后端返回的业务错误如“用户名或密码错误”“参数校验失败”直接显示后端返回的错误信息。2. 统一异常处理实现在 DioUtil 中封装异常处理方法并在业务层通过try/catch捕获并处理// 1. 定义异常类型枚举便于业务层判断enumNetworkErrorType{networkError,// 网络错误timeout,// 超时httpError,// HTTP 错误businessError,// 业务错误cancel,// 请求取消unknown,// 未知错误}// 2. 自定义异常类classNetworkExceptionimplementsException{finalNetworkErrorType type;finalString message;NetworkException({requiredthis.type,requiredthis.message});overrideStringtoString()NetworkException: $type, message: $message;}// 3. 在 DioUtil 中统一转换异常void_handleDioError(DioException e){if(CancelToken.isCancel(e)){throwNetworkException(type:NetworkErrorType.cancel,message:e.message??请求已取消);}switch(e.type){caseDioExceptionType.connectionError:throwNetworkException(type:NetworkErrorType.networkError,message:网络错误请检查网络连接);caseDioExceptionType.connectionTimeout:caseDioExceptionType.receiveTimeout:caseDioExceptionType.sendTimeout:throwNetworkException(type:NetworkErrorType.timeout,message:请求超时请稍后重试);caseDioExceptionType.badResponse:finalint statusCodee.response?.statusCode??0;throwNetworkException(type:NetworkErrorType.httpError,message:服务器错误$statusCode请稍后重试,);default:throwNetworkException(type:NetworkErrorType.unknown,message:e.message??未知错误);}}// 4. 业务层处理异常FuturevoidfetchData()async{try{finaldataawaitApiService.getUserList();// 处理正常数据}onNetworkExceptioncatch(e){// 根据异常类型显示不同提示switch(e.type){caseNetworkErrorType.networkError:_showToast(e.message);break;caseNetworkErrorType.timeout:_showToast(e.message);break;caseNetworkErrorType.cancel:// 无需提示break;default:_showToast(e.message);}}}六、总结与最佳实践Dio 作为 Flutter 网络请求的首选库其强大的功能与灵活的扩展性能够满足从简单到复杂的所有网络场景需求。结合本文内容总结以下最佳实践采用“工具类 接口层 模型层”的分层封装方案提升代码可维护性合理使用拦截器实现 Token 管理、日志打印、缓存处理减少重复代码通过CancelToken取消无效请求避免内存泄漏与数据错乱统一异常处理机制区分网络异常、HTTP 异常与业务异常提升用户体验使用环境变量管理baseUrl区分开发/测试/生产环境避免硬编码配合json_serializable实现 JSON 序列化减少手动解析错误。通过以上方案可构建一套稳定、高效、易维护的 Flutter 网络请求体系为应用的后续迭代与扩展奠定坚实基础。
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

美术馆网站建设总体要求如何在网站中做二级下拉菜单

你是否曾经看着硬盘里堆积如山的游戏映像文件发愁?那些动辄4.7GB的GameCube游戏和8.5GB的Wii游戏,正在无情地吞噬着宝贵的存储空间。今天,我们将揭开Dolphin模拟器格式转换的神秘面纱,让你的游戏库实现从臃肿到精干的华丽转身。 【…

张小明 2025/12/25 2:25:34 网站建设

做百度移动端网站wordpress警告函数未被定义

城通网盘解析终极指南:三步实现文件下载优化 【免费下载链接】ctfileGet 获取城通网盘一次性直连地址 项目地址: https://gitcode.com/gh_mirrors/ct/ctfileGet 还在为城通网盘的繁琐下载流程而烦恼吗?这款城通网盘解析工具将彻底改变你的文件下载…

张小明 2025/12/25 2:25:50 网站建设

微信做兼职什么网站好四川建设厅

3分钟快速部署wvp-GB28181-pro:企业级视频监控平台终极指南 【免费下载链接】wvp-GB28181-pro 项目地址: https://gitcode.com/GitHub_Trending/wv/wvp-GB28181-pro wvp-GB28181-pro是一款完全开源的国标视频监控平台,基于GB/T 28181-2016标准设…

张小明 2025/12/25 1:45:20 网站建设

怪兽网站模板高邮市建设网站

OpenCVSharp实战指南:快速掌握.NET计算机视觉开发技术 【免费下载链接】opencvsharp shimat/opencvsharp: OpenCvSharp 是一个开源的 C# 绑定库,它封装了 OpenCV(一个著名的计算机视觉库),使得开发者能够方便地在 .NET…

张小明 2025/12/24 16:14:11 网站建设

高质量的扬中网站建设高明网站制作

还在为收集不到心仪的角色皮肤而烦恼吗?🎮 这款麻雀魂全解锁神器让你告别肝任务和氪金的烦恼,轻松拥有所有角色和装扮!无论你在哪个服务器,都能完美适配,让你的游戏体验瞬间升级! 【免费下载链接…

张小明 2025/12/24 23:20:47 网站建设

安徽做手机网站阿里巴巴1688网站做店铺

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

张小明 2025/12/25 2:12:44 网站建设