Flutter网络请求完全指南
Flutter网络请求完全指南引言在现代移动应用开发中网络请求是不可或缺的一部分它允许应用与服务器进行数据交互实现各种功能。Flutter提供了多种网络请求方案从基础的http包到功能强大的dio库都可以帮助你实现各种网络交互需求。本文将深入探讨Flutter网络请求的核心概念、实现方法和最佳实践帮助你构建更加可靠、高效的网络应用。网络请求库1. http 包Flutter官方推荐的基础网络请求库// 安装依赖http: ^0.13.0 import package:http/http.dart as http; import dart:convert; // GET请求 Futurevoid fetchData() async { final response await http.get(Uri.parse(https://api.example.com/data)); if (response.statusCode 200) { // 成功 final data jsonDecode(response.body); print(data); } else { // 失败 print(请求失败: ${response.statusCode}); } } // POST请求 Futurevoid postData() async { final response await http.post( Uri.parse(https://api.example.com/data), headers: { Content-Type: application/json, }, body: jsonEncode({ name: John Doe, email: johnexample.com, }), ); if (response.statusCode 201) { // 成功 final data jsonDecode(response.body); print(data); } else { // 失败 print(请求失败: ${response.statusCode}); } }2. dio 包功能更强大的网络请求库支持拦截器、取消请求等高级功能// 安装依赖dio: ^4.0.0 import package:dio/dio.dart; // 创建dio实例 final dio Dio(); // GET请求 Futurevoid fetchData() async { try { final response await dio.get(https://api.example.com/data); print(response.data); } catch (e) { print(请求失败: $e); } } // POST请求 Futurevoid postData() async { try { final response await dio.post(https://api.example.com/data, data: { name: John Doe, email: johnexample.com, }, ); print(response.data); } catch (e) { print(请求失败: $e); } }高级网络请求技巧1. 拦截器使用拦截器处理请求和响应// 添加拦截器 dio.interceptors.add(InterceptorsWrapper( onRequest: (options, handler) { // 在发送请求之前做一些处理 print(请求: ${options.uri}); // 添加认证头 options.headers[Authorization] Bearer token; return handler.next(options); }, onResponse: (response, handler) { // 在收到响应后做一些处理 print(响应: ${response.statusCode}); return handler.next(response); }, onError: (DioError e, handler) { // 处理错误 print(错误: ${e.message}); return handler.next(e); }, ));2. 请求取消取消正在进行的请求// 创建取消令牌 final cancelToken CancelToken(); // 发起请求 Futurevoid fetchData() async { try { final response await dio.get(https://api.example.com/data, cancelToken: cancelToken, ); print(response.data); } catch (e) { if (CancelToken.isCancel(e)) { print(请求被取消); } else { print(请求失败: $e); } } } // 取消请求 void cancelRequest() { cancelToken.cancel(主动取消请求); }3. 超时设置设置请求超时// 全局设置 dio.options.connectTimeout Duration(seconds: 5); dio.options.receiveTimeout Duration(seconds: 3); // 单次请求设置 final response await dio.get(https://api.example.com/data, options: Options( connectTimeout: Duration(seconds: 5), receiveTimeout: Duration(seconds: 3), ), );4. 重试机制实现请求重试// 添加重试拦截器 dio.interceptors.add(RetryInterceptor( dio: dio, retries: 3, // 重试次数 retryDelays: [ // 重试间隔 Duration(seconds: 1), Duration(seconds: 2), Duration(seconds: 3), ], retryEvaluator: (error) { // 只有特定错误才重试 return error.type DioErrorType.connectTimeout || error.type DioErrorType.receiveTimeout; }, )); // RetryInterceptor实现 class RetryInterceptor extends Interceptor { final Dio dio; final int retries; final ListDuration retryDelays; final RetryEvaluator retryEvaluator; RetryInterceptor({ required this.dio, this.retries 3, required this.retryDelays, required this.retryEvaluator, }); override void onError(DioError err, ErrorInterceptorHandler handler) async { if (err.requestOptions.disableRetry ?? false) { return handler.next(err); } final retryCount err.requestOptions.extra[retryCount] ?? 0; if (retryCount retries retryEvaluator(err)) { err.requestOptions.extra[retryCount] retryCount 1; await Future.delayed(retryDelays[min(retryCount, retryDelays.length - 1)]); try { final response await dio.fetch(err.requestOptions); return handler.resolve(response); } catch (e) { return handler.next(err); } } return handler.next(err); } } typedef RetryEvaluator bool Function(DioError error);网络请求状态管理1. 基础状态管理使用FutureBuilder处理网络请求状态class DataScreen extends StatelessWidget { Futuredynamic fetchData() async { final response await http.get(Uri.parse(https://api.example.com/data)); if (response.statusCode 200) { return jsonDecode(response.body); } else { throw Exception(Failed to load data); } } override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(数据展示)), body: FutureBuilder( future: fetchData(), builder: (context, snapshot) { if (snapshot.connectionState ConnectionState.waiting) { return Center(child: CircularProgressIndicator()); } else if (snapshot.hasError) { return Center(child: Text(错误: ${snapshot.error})); } else if (snapshot.hasData) { final data snapshot.data; return ListView.builder( itemCount: data.length, itemBuilder: (context, index) { return ListTile( title: Text(data[index][name]), subtitle: Text(data[index][email]), ); }, ); } else { return Center(child: Text(无数据)); } }, ), ); } }2. 使用Provider管理网络状态// 创建数据模型 class DataModel extends ChangeNotifier { Listdynamic _data []; bool _isLoading false; String? _error; Listdynamic get data _data; bool get isLoading _isLoading; String? get error _error; Futurevoid fetchData() async { _isLoading true; _error null; notifyListeners(); try { final response await http.get(Uri.parse(https://api.example.com/data)); if (response.statusCode 200) { _data jsonDecode(response.body); } else { _error 请求失败: ${response.statusCode}; } } catch (e) { _error 请求失败: $e; } finally { _isLoading false; notifyListeners(); } } } // 使用 class DataScreen extends StatelessWidget { override Widget build(BuildContext context) { final dataModel Provider.ofDataModel(context); return Scaffold( appBar: AppBar(title: Text(数据展示)), body: Column( children: [ ElevatedButton( onPressed: dataModel.fetchData, child: Text(获取数据), ), if (dataModel.isLoading) Center(child: CircularProgressIndicator()), if (dataModel.error ! null) Center(child: Text(错误: ${dataModel.error})), if (!dataModel.isLoading dataModel.error null) Expanded( child: ListView.builder( itemCount: dataModel.data.length, itemBuilder: (context, index) { return ListTile( title: Text(dataModel.data[index][name]), subtitle: Text(dataModel.data[index][email]), ); }, ), ), ], ), ); } }实战应用1. 用户认证class AuthService { final dio Dio(); AuthService() { // 配置基础URL dio.options.baseUrl https://api.example.com; // 添加拦截器 dio.interceptors.add(InterceptorsWrapper( onRequest: (options, handler) { // 从本地存储获取token final token LocalStorage.getToken(); if (token ! null) { options.headers[Authorization] Bearer $token; } return handler.next(options); }, )); } // 登录 FutureMapString, dynamic login(String email, String password) async { final response await dio.post(/auth/login, data: { email: email, password: password, }, ); // 存储token LocalStorage.saveToken(response.data[token]); return response.data; } // 注册 FutureMapString, dynamic register(String name, String email, String password) async { final response await dio.post(/auth/register, data: { name: name, email: email, password: password, }, ); return response.data; } // 获取用户信息 FutureMapString, dynamic getUserInfo() async { final response await dio.get(/user/profile); return response.data; } } // 本地存储 class LocalStorage { static const _tokenKey auth_token; static Futurevoid saveToken(String token) async { final prefs await SharedPreferences.getInstance(); await prefs.setString(_tokenKey, token); } static FutureString? getToken() async { final prefs await SharedPreferences.getInstance(); return prefs.getString(_tokenKey); } static Futurevoid removeToken() async { final prefs await SharedPreferences.getInstance(); await prefs.remove(_tokenKey); } }2. 商品列表class ProductService { final dio Dio(); ProductService() { dio.options.baseUrl https://api.example.com; } // 获取商品列表 FutureListProduct getProducts({int page 1, int limit 10}) async { final response await dio.get(/products, queryParameters: { page: page, limit: limit, }, ); return (response.data[data] as List) .map((item) Product.fromJson(item)) .toList(); } // 获取商品详情 FutureProduct getProductById(int id) async { final response await dio.get(/products/$id); return Product.fromJson(response.data); } // 搜索商品 FutureListProduct searchProducts(String keyword) async { final response await dio.get(/products/search, queryParameters: { keyword: keyword, }, ); return (response.data[data] as List) .map((item) Product.fromJson(item)) .toList(); } } class Product { final int id; final String name; final double price; final String description; final String imageUrl; Product({ required this.id, required this.name, required this.price, required this.description, required this.imageUrl, }); factory Product.fromJson(MapString, dynamic json) { return Product( id: json[id], name: json[name], price: json[price].toDouble(), description: json[description], imageUrl: json[image_url], ); } }3. 文件上传Futurevoid uploadFile(File file) async { final formData FormData.fromMap({ file: await MultipartFile.fromFile(file.path, filename: upload.jpg), description: 上传的文件, }); try { final response await dio.post(https://api.example.com/upload, data: formData, onSendProgress: (int sent, int total) { print(上传进度: ${(sent / total * 100).toStringAsFixed(0)}%); }, ); print(上传成功: ${response.data}); } catch (e) { print(上传失败: $e); } }4. 网络状态监测import package:connectivity_plus/connectivity_plus.dart; class NetworkService { final Connectivity _connectivity Connectivity(); StreamConnectivityResult get connectivityStream _connectivity.onConnectivityChanged; FutureConnectivityResult checkConnectivity() async { return await _connectivity.checkConnectivity(); } Futurebool isConnected() async { final result await checkConnectivity(); return result ! ConnectivityResult.none; } } // 使用 class HomeScreen extends StatefulWidget { override _HomeScreenState createState() _HomeScreenState(); } class _HomeScreenState extends StateHomeScreen { late StreamSubscriptionConnectivityResult _subscription; ConnectivityResult _connectivityResult ConnectivityResult.none; override void initState() { super.initState(); _subscription NetworkService().connectivityStream.listen((result) { setState(() { _connectivityResult result; }); }); } override void dispose() { _subscription.cancel(); super.dispose(); } override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(网络状态监测)), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(当前网络状态: ${_connectivityResult.toString()}), SizedBox(height: 20), ElevatedButton( onPressed: () async { final isConnected await NetworkService().isConnected(); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(isConnected ? 网络连接正常 : 无网络连接)), ); }, child: Text(检查网络连接), ), ], ), ), ); } }性能优化使用缓存缓存频繁访问的数据减少网络请求压缩数据使用gzip压缩减少数据传输量批量请求合并多个请求减少网络连接次数图片优化使用适当尺寸的图片考虑使用WebP格式后台请求将非关键请求放在后台执行网络状态监测根据网络状态调整请求策略重试机制对临时网络错误进行重试取消无用请求如页面切换时取消未完成的请求最佳实践封装网络服务创建专门的网络服务类集中管理网络请求统一错误处理使用拦截器统一处理网络错误使用模型类将JSON数据转换为强类型的模型类添加超时设置避免请求无限等待实现重试机制提高请求成功率使用安全连接优先使用HTTPS处理认证安全存储和使用认证令牌监控网络请求记录和分析网络请求性能测试网络请求为网络请求编写单元测试考虑离线模式实现离线缓存和同步机制总结Flutter提供了多种网络请求方案从基础的http包到功能强大的dio库都可以帮助你实现各种网络交互需求。通过本文的介绍你应该已经掌握了基本的网络请求实现方法高级网络请求技巧如拦截器、取消请求和重试机制网络请求状态管理实战应用如用户认证、商品列表和文件上传网络状态监测性能优化和最佳实践通过合理使用这些技术你可以构建出更加可靠、高效的网络应用为用户提供更好的体验。在实际项目中要根据具体需求选择合适的网络请求方案并结合状态管理库来管理网络请求状态确保应用的稳定性和性能。