逆袭做富豪官方网站WordPress 升级 php
逆袭做富豪官方网站,WordPress 升级 php,东莞房价二手房,调取当前文章标签wordpress欢迎大家加入[开源鸿蒙跨平台开发者社区](https://openharmonycrossplatform.csdn.net)#xff0c;一起共建开源鸿蒙跨平台生态。网络请求是 Flutter 应用与后端交互的 “桥梁”—— 登录、数据展示、文件上传下载等核心功能都离不开网络请求。但很多开发者仅停留在 “能请求”…欢迎大家加入[开源鸿蒙跨平台开发者社区](https://openharmonycrossplatform.csdn.net)一起共建开源鸿蒙跨平台生态。网络请求是 Flutter 应用与后端交互的 “桥梁”—— 登录、数据展示、文件上传下载等核心功能都离不开网络请求。但很多开发者仅停留在 “能请求” 的层面忽略了异常处理、请求拦截、数据缓存、断点续传等关键场景。本文将从基础的 GET/POST 请求入手逐步实现拦截器、请求缓存、文件断点续传等进阶功能既有严谨的代码规范又有生动的场景拆解让你彻底掌握 Flutter 网络请求的精髓。一、Flutter 网络请求核心认知为什么选择 Dio先理清 Flutter 网络请求的核心逻辑明确技术选型的底层逻辑原生 HttpClient 的痛点原生HttpClientAPI 繁琐不支持拦截器、FormData、文件上传等高级功能需手动处理序列化 / 反序列化Dio 的优势Dio 是 Flutter 生态中最主流的网络请求库支持拦截器、FormData、文件上传下载、超时控制、取消请求等API 简洁且扩展性强核心设计原则网络请求需遵循 “异常兜底、数据解析、状态管理” 三位一体的原则避免崩溃和数据错乱。本文所有代码基于plaintextFlutter 3.26.0 Dart 3.6.0 dio: ^5.5.0 shared_preferences: ^2.2.2 # 缓存存储 path_provider: ^2.1.2 # 本地文件路径二、入门基础 GET/POST 请求 数据解析先实现最基础的 GET/POST 请求掌握 Dio 的核心用法和 JSON 数据解析这是网络请求的基础模板。2.1 第一步封装基础 Dio 实例创建utils/dio_client.dart封装全局 Dio 实例统一配置基础参数dartimport package:dio/dio.dart; // 全局Dio实例封装 class DioClient { static late Dio _dio; // 初始化Dio配置 static void init() { _dio Dio( BaseOptions( // 基础URL实际开发中替换为真实接口地址 baseUrl: https://api.example.com/v1, // 连接超时时间 connectTimeout: const Duration(seconds: 5), // 接收超时时间 receiveTimeout: const Duration(seconds: 3), // 响应数据类型 responseType: ResponseType.json, // 请求头 headers: { Content-Type: application/json, Accept: application/json, }, ), ); } // 获取Dio实例 static Dio get instance _dio; // 简化GET请求 static FutureT getT( String path, { MapString, dynamic? queryParameters, Options? options, CancelToken? cancelToken, }) async { try { final response await _dio.get( path, queryParameters: queryParameters, options: options, cancelToken: cancelToken, ); return response.data as T; } on DioException catch (e) { throw _handleDioError(e); } } // 简化POST请求 static FutureT postT( String path, { dynamic data, MapString, dynamic? queryParameters, Options? options, CancelToken? cancelToken, }) async { try { final response await _dio.post( path, data: data, queryParameters: queryParameters, options: options, cancelToken: cancelToken, ); return response.data as T; } on DioException catch (e) { throw _handleDioError(e); } } // 统一异常处理 static String _handleDioError(DioException e) { switch (e.type) { case DioExceptionType.connectionTimeout: return 网络连接超时请检查网络; case DioExceptionType.receiveTimeout: return 数据接收超时请稍后重试; case DioExceptionType.badResponse: return 接口返回错误${e.response?.statusCode}; case DioExceptionType.cancel: return 请求已取消; case DioExceptionType.connectionError: return 网络连接失败请检查网络; default: return 请求失败${e.message ?? 未知错误}; } } }代码解析全局单例 Dio通过静态方法init初始化 Dio避免重复创建实例BaseOptions 配置统一设置基础 URL、超时时间、请求头等减少重复代码简化 GET/POST 方法封装通用请求方法自动处理异常并抛出友好提示统一异常处理将 Dio 的各类异常转换为用户友好的提示文字避免直接抛出技术异常。2.2 第二步初始化 Dio 并实现基础请求修改main.dart在应用启动时初始化 Diodartimport package:flutter/material.dart; import utils/dio_client.dart; import pages/network_demo_page.dart; void main() async { WidgetsFlutterBinding.ensureInitialized(); // 初始化Dio DioClient.init(); runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); override Widget build(BuildContext context) { return MaterialApp( title: Flutter网络请求实战, theme: ThemeData(primarySwatch: Colors.blue), home: const NetworkDemoPage(), ); } }2.3 第三步实现 GET/POST 请求与数据解析创建pages/network_demo_page.dart实现用户列表 GET 请求和用户创建 POST 请求dartimport package:flutter/material.dart; import utils/dio_client.dart; // 数据模型用户 class User { final int id; final String name; final String email; User({required this.id, required this.name, required this.email}); // 从JSON解析模型 factory User.fromJson(MapString, dynamic json) { return User( id: json[id], name: json[name], email: json[email], ); } // 转换为JSON MapString, dynamic toJson() { return { id: id, name: name, email: email, }; } } class NetworkDemoPage extends StatefulWidget { const NetworkDemoPage({super.key}); override StateNetworkDemoPage createState() _NetworkDemoPageState(); } class _NetworkDemoPageState extends StateNetworkDemoPage { // 加载状态 bool _isLoading false; // 用户列表 ListUser _userList []; // 错误提示 String? _errorMsg; // 获取用户列表GET请求 Futurevoid _fetchUserList() async { setState(() { _isLoading true; _errorMsg null; }); try { // 发起GET请求模拟接口/users final response await DioClient.getMapString, dynamic( /users, queryParameters: {page: 1, size: 10}, // 请求参数 ); // 解析JSON数据 final Listdynamic dataList response[data]; setState(() { _userList dataList.map((json) User.fromJson(json)).toList(); }); } catch (e) { setState(() { _errorMsg e.toString(); }); } finally { setState(() { _isLoading false; }); } } // 创建用户POST请求 Futurevoid _createUser() async { setState(() { _isLoading true; _errorMsg null; }); try { // 构建请求体 final userData User( id: 0, // 后端生成ID name: Flutter测试用户, email: flutter_testexample.com, ).toJson(); // 发起POST请求 await DioClient.post( /users, data: userData, ); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text(用户创建成功)), ); // 重新获取用户列表 _fetchUserList(); } } catch (e) { setState(() { _errorMsg e.toString(); }); } finally { setState(() { _isLoading false; }); } } override void initState() { super.initState(); // 页面加载时获取用户列表 _fetchUserList(); } override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text(基础网络请求)), body: Padding( padding: const EdgeInsets.all(16), child: Column( children: [ // 操作按钮 Row( children: [ ElevatedButton( onPressed: _isLoading ? null : _fetchUserList, child: const Text(刷新用户列表), ), const SizedBox(width: 16), ElevatedButton( onPressed: _isLoading ? null : _createUser, child: const Text(创建测试用户), ), ], ), const SizedBox(height: 20), // 加载状态/错误提示/用户列表 _isLoading ? const Center(child: CircularProgressIndicator()) : _errorMsg ! null ? Center( child: Text( _errorMsg!, style: const TextStyle(color: Colors.red, fontSize: 16), ), ) : Expanded( child: ListView.builder( itemCount: _userList.length, itemBuilder: (context, index) { final user _userList[index]; return ListTile( key: ValueKey(user.id), title: Text(user.name), subtitle: Text(user.email), ); }, ), ), ], ), ), ); } }核心解析数据模型设计定义User模型类通过fromJson/toJson方法实现 JSON 与模型的互转避免直接操作 Map提升代码可读性模型类的字段与接口返回字段一一对应减少解析错误。请求状态管理通过_isLoading控制加载状态避免重复请求_errorMsg存储错误提示友好展示给用户所有异步操作包裹在try-catch中防止崩溃。请求参数处理GET 请求通过queryParameters传递 URL 参数POST 请求通过data传递 JSON 请求体所有请求都关联页面生命周期通过mounted判断页面是否挂载。三、进阶拦截器实现 请求 / 响应统一处理拦截器是 Dio 的核心特性可实现请求头自动添加、响应数据统一解析、Token 过期自动刷新等功能是企业级开发的必备技能。3.1 实现通用拦截器修改utils/dio_client.dart添加请求拦截器和响应拦截器dartimport package:dio/dio.dart; class DioClient { static late Dio _dio; static void init() { _dio Dio( BaseOptions( baseUrl: https://api.example.com/v1, connectTimeout: const Duration(seconds: 5), receiveTimeout: const Duration(seconds: 3), responseType: ResponseType.json, headers: { Content-Type: application/json, Accept: application/json, }, ), ); // 添加请求拦截器 _dio.interceptors.add( InterceptorsWrapper( // 请求发送前拦截 onRequest: (RequestOptions options, RequestInterceptorHandler handler) { // 1. 自动添加Token实际开发中从本地存储获取 final token your_token_here; if (token.isNotEmpty) { options.headers[Authorization] Bearer $token; } // 2. 打印请求日志调试用 debugPrint(请求URL${options.uri}); debugPrint(请求参数${options.data}); // 继续执行请求 handler.next(options); }, // 响应返回后拦截 onResponse: (Response response, ResponseInterceptorHandler handler) { // 1. 统一解析响应数据假设接口返回格式{code: 200, data: ..., msg: } final MapString, dynamic responseData response.data; if (responseData[code] 200) { // 只返回data部分简化上层解析 response.data responseData[data]; } else { // 非200状态码抛出异常 handler.reject( DioException( requestOptions: response.requestOptions, response: response, type: DioExceptionType.badResponse, message: responseData[msg] ?? 接口返回错误, ), true, ); return; } // 2. 打印响应日志 debugPrint(响应数据${response.data}); // 继续处理响应 handler.next(response); }, // 请求失败时拦截 onError: (DioException e, ErrorInterceptorHandler handler) { // 1. Token过期自动刷新示例逻辑 if (e.response?.statusCode 401) { // 这里可实现Token刷新逻辑刷新后重新发起请求 debugPrint(Token过期准备刷新); // 简化处理直接抛出未登录异常 handler.reject( DioException( requestOptions: e.requestOptions, message: 登录状态已过期请重新登录, type: DioExceptionType.badResponse, ), true, ); return; } // 2. 统一错误处理 handler.next(e); }, ), ); } // 其余代码不变... }拦截器核心逻辑解析请求拦截器onRequest自动添加 Authorization 请求头无需在每个请求中手动设置打印请求日志便于调试可扩展添加请求加密、参数签名等逻辑。响应拦截器onResponse统一解析接口返回格式假设接口返回{code: 200, data: ..., msg: }只向上层返回data部分简化解析逻辑非 200 状态码直接抛出异常上层只需处理业务逻辑。错误拦截器onError捕获 401 状态码实现 Token 过期自动刷新示例中简化为提示重新登录可扩展添加重试机制、错误日志上报等。3.2 拦截器使用效果添加拦截器后上层代码无需关心Token 的添加拦截器自动注入响应数据的统一解析直接获取data部分Token 过期处理拦截器统一捕获并提示。四、高阶 1请求缓存实现避免重复请求实际开发中对于不常变化的数据如首页分类、用户信息可添加缓存逻辑减少网络请求提升页面加载速度。4.1 封装缓存工具类创建utils/cache_manager.dartdartimport package:shared_preferences/shared_preferences.dart; import dart:convert; // 缓存管理工具 class CacheManager { static late SharedPreferences _prefs; // 初始化 static Futurevoid init() async { _prefs await SharedPreferences.getInstance(); } // 保存缓存 static Futurevoid setCache(String key, dynamic data, {Duration? expireTime}) { final cacheData { data: data, timestamp: DateTime.now().millisecondsSinceEpoch, expireTime: expireTime?.inMilliseconds ?? 0, }; return _prefs.setString(key, json.encode(cacheData)); } // 获取缓存 static dynamic getCache(String key) { final cacheStr _prefs.getString(key); if (cacheStr null) return null; final cacheData json.decode(cacheStr); final timestamp cacheData[timestamp] as int; final expireTime cacheData[expireTime] as int; // 判断是否过期 if (expireTime 0) { final now DateTime.now().millisecondsSinceEpoch; if (now - timestamp expireTime) { // 过期则删除缓存 removeCache(key); return null; } } return cacheData[data]; } // 删除缓存 static Futurevoid removeCache(String key) { return _prefs.remove(key); } // 清空所有缓存 static Futurevoid clearAllCache() { return _prefs.clear(); } }4.2 实现带缓存的 GET 请求修改utils/dio_client.dart添加带缓存的 GET 请求方法dart// 带缓存的GET请求 static FutureT getWithCacheT( String path, { MapString, dynamic? queryParameters, Options? options, CancelToken? cancelToken, Duration? cacheDuration const Duration(minutes: 10), // 默认缓存10分钟 }) async { // 构建缓存key final cacheKey $path-${json.encode(queryParameters ?? {})}; // 先从缓存获取 final cacheData CacheManager.getCache(cacheKey); if (cacheData ! null) { return cacheData as T; } // 缓存未命中发起网络请求 try { final response await _dio.get( path, queryParameters: queryParameters, options: options, cancelToken: cancelToken, ); // 保存缓存 await CacheManager.setCache(cacheKey, response.data, expireTime: cacheDuration); return response.data as T; } on DioException catch (e) { throw _handleDioError(e); } }4.3 使用带缓存的请求在NetworkDemoPage中替换_fetchUserList方法dartFuturevoid _fetchUserList() async { setState(() { _isLoading true; _errorMsg null; }); try { // 使用带缓存的GET请求 final response await DioClient.getWithCacheMapString, dynamic( /users, queryParameters: {page: 1, size: 10}, cacheDuration: const Duration(minutes: 5), // 缓存5分钟 ); final Listdynamic dataList response[data]; setState(() { _userList dataList.map((json) User.fromJson(json)).toList(); }); } catch (e) { setState(() { _errorMsg e.toString(); }); } finally { setState(() { _isLoading false; }); } }缓存逻辑解析缓存 Key 由请求路径 参数组成避免不同参数的请求缓存冲突优先读取缓存缓存未命中或过期时才发起网络请求缓存时长可自定义灵活适配不同业务场景。五、高阶 2文件断点续传下载文件下载是高频场景断点续传能避免网络中断后重新下载提升用户体验。5.1 封装断点续传下载工具创建utils/download_manager.dartdartimport package:dio/dio.dart; import package:path_provider/path_provider.dart; import dart:io; // 下载进度回调 typedef DownloadProgressCallback void Function(int count, int total); // 断点续传下载管理器 class DownloadManager { // 开始下载 static Futurevoid downloadFile( String url, String saveFileName, { required DownloadProgressCallback onProgress, required Function(String path) onSuccess, required Function(String error) onError, }) async { try { // 获取本地存储路径 final directory await getExternalStorageDirectory(); if (directory null) { onError(无法获取存储路径); return; } final savePath ${directory.path}/$saveFileName; final file File(savePath); int start 0; // 如果文件已存在获取文件大小作为起始位置 if (file.existsSync()) { start file.lengthSync(); } // 发起断点续传请求 final dio Dio(); await dio.download( url, savePath, options: Options( headers: { Range: bytes$start-, // 断点续传核心指定起始字节 }, ), onReceiveProgress: onProgress, // 追加写入文件 deleteOnError: false, ); onSuccess(savePath); } catch (e) { onError(e.toString()); } } }5.2 实现文件下载页面创建pages/download_page.dartdartimport package:flutter/material.dart; import utils/download_manager.dart; class DownloadPage extends StatefulWidget { const DownloadPage({super.key}); override StateDownloadPage createState() _DownloadPageState(); } class _DownloadPageState extends StateDownloadPage { // 下载进度 double _progress 0.0; // 下载状态 bool _isDownloading false; // 下载提示 String _downloadMsg 未开始下载; // 开始下载 void _startDownload() { setState(() { _isDownloading true; _progress 0.0; _downloadMsg 下载中...; }); // 模拟下载地址实际替换为真实文件地址 const downloadUrl https://example.com/file/test.pdf; const fileName test.pdf; DownloadManager.downloadFile( downloadUrl, fileName, onProgress: (count, total) { if (total 0) return; setState(() { _progress count / total; _downloadMsg 下载中${(count / total * 100).toStringAsFixed(1)}%; }); }, onSuccess: (path) { setState(() { _isDownloading false; _downloadMsg 下载完成$path; }); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text(文件下载成功)), ); }, onError: (error) { setState(() { _isDownloading false; _downloadMsg 下载失败$error; }); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(下载失败$error)), ); }, ); } override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text(断点续传下载)), body: Padding( padding: const EdgeInsets.all(16), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // 下载进度条 LinearProgressIndicator( value: _progress, minHeight: 10, backgroundColor: Colors.grey[200], valueColor: const AlwaysStoppedAnimationColor(Colors.blue), ), const SizedBox(height: 20), // 下载状态提示 Text( _downloadMsg, style: const TextStyle(fontSize: 16), ), const SizedBox(height: 40), // 下载按钮 ElevatedButton( onPressed: _isDownloading ? null : _startDownload, style: ElevatedButton.styleFrom( padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 12), ), child: const Text(开始下载文件), ), ], ), ), ); } }断点续传核心解析Range请求头指定bytes$start-告诉服务器从指定字节开始传输实现断点续传文件追加写入deleteOnError: false确保下载中断后文件不被删除下次可继续下载进度回调onReceiveProgress实时获取下载进度更新 UI 展示。六、网络请求避坑指南异常处理所有网络请求必须包裹try-catch避免未捕获异常导致崩溃区分网络异常、接口异常、业务异常分别给出友好提示内存泄漏使用CancelToken取消未完成的请求如页面销毁时异步回调中必须判断mounted避免操作已销毁的页面缓存策略缓存只适用于非敏感、不常变化的数据如分类、配置敏感数据如用户信息禁止缓存或设置极短的缓存时长断点续传确保服务器支持Range请求头否则断点续传无效大文件下载建议分块下载避免内存溢出调试技巧使用 Dio 的日志拦截器LogInterceptor打印完整的请求 / 响应日志测试时模拟各种异常场景断网、超时、401/404/500。七、总结Flutter 网络请求的学习路径是 “基础请求→拦截器→缓存→高级功能”核心原则是 “统一封装、异常兜底、体验优先”基础请求封装全局 Dio 实例统一处理请求参数和数据解析拦截器实现请求头自动添加、响应统一解析、Token 过期处理缓存策略减少重复请求提升页面加载速度高级功能断点续传下载、文件上传、取消请求等适配复杂业务场景。网络请求是 Flutter 应用的 “生命线”写得规范与否直接影响应用的稳定性和用户体验。比如统一的异常处理能避免崩溃缓存策略能提升加载速度断点续传能优化大文件下载体验。希望本文的实战案例和原理解析能让你避开网络请求的 “坑”写出既严谨又高性能的 Flutter 网络请求代码。