news 2026/5/22 1:37:08

Flutter网络请求完全指南:从dio到RESTful API

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Flutter网络请求完全指南:从dio到RESTful API

引言

网络请求是现代应用的核心功能之一。Flutter提供了多种方式来处理网络请求,从原生的http包到功能强大的dio库。本文将深入探讨Flutter网络请求的最佳实践,帮助你构建健壮的网络层。

一、网络请求基础

1.1 选择合适的库

特点适用场景
http官方包,轻量级简单请求
dio功能强大,支持拦截器复杂场景
retrofit类型安全,代码生成大型项目

1.2 基本HTTP请求

import 'package:http/http.dart' as http; Future<void> fetchData() async { final response = await http.get( Uri.parse('https://api.example.com/data'), headers: {'Authorization': 'Bearer token'}, ); if (response.statusCode == 200) { print(response.body); } else { throw Exception('请求失败'); } }

1.3 POST请求

Future<void> postData() async { final response = await http.post( Uri.parse('https://api.example.com/data'), headers: {'Content-Type': 'application/json'}, body: jsonEncode({'name': 'John', 'age': 30}), ); }

二、dio库详解

2.1 安装与配置

dependencies: dio: ^5.0.0
import 'package:dio/dio.dart'; final dio = Dio();

2.2 基本配置

final dio = Dio( BaseOptions( baseUrl: 'https://api.example.com', connectTimeout: const Duration(seconds: 5), receiveTimeout: const Duration(seconds: 3), headers: { 'Content-Type': 'application/json', }, ), );

2.3 GET请求

Future<User> getUser(String id) async { try { final response = await dio.get('/users/$id'); return User.fromJson(response.data); } catch (e) { throw Exception('获取用户失败: $e'); } }

2.4 POST请求

Future<User> createUser(User user) async { final response = await dio.post( '/users', data: user.toJson(), ); return User.fromJson(response.data); }

三、拦截器

3.1 请求拦截器

dio.interceptors.add(InterceptorsWrapper( onRequest: (options, handler) { options.headers['Authorization'] = 'Bearer ${AuthService.token}'; return handler.next(options); }, ));

3.2 响应拦截器

dio.interceptors.add(InterceptorsWrapper( onResponse: (response, handler) { if (response.statusCode == 401) { AuthService.refreshToken(); } return handler.next(response); }, ));

3.3 错误拦截器

dio.interceptors.add(InterceptorsWrapper( onError: (error, handler) { if (error.response?.statusCode == 500) { showError('服务器错误'); } return handler.next(error); }, ));

3.4 日志拦截器

dio.interceptors.add(LogInterceptor( requestBody: true, responseBody: true, ));

四、错误处理

4.1 统一错误处理

class ApiException implements Exception { final String message; final int? statusCode; ApiException(this.message, {this.statusCode}); @override String toString() => 'ApiException: $message'; } Future<T> safeApiCall<T>(Future<T> Function() apiCall) async { try { return await apiCall(); } on DioError catch (e) { throw ApiException( e.response?.data['message'] ?? '网络请求失败', statusCode: e.response?.statusCode, ); } catch (e) { throw ApiException(e.toString()); } }

4.2 重试机制

dio.interceptors.add(RetryInterceptor( retries: 3, retryDelay: const Duration(seconds: 1), retryEvaluator: (error) => error.response?.statusCode == 500, ));

五、请求取消

5.1 取消单个请求

CancelToken cancelToken = CancelToken(); dio.get('/data', cancelToken: cancelToken); // 取消请求 cancelToken.cancel('请求已取消');

5.2 取消多个请求

final cancelToken = CancelToken(); // 多个请求使用同一个cancelToken dio.get('/data1', cancelToken: cancelToken); dio.get('/data2', cancelToken: cancelToken); // 取消所有请求 cancelToken.cancel('全部取消');

六、文件上传下载

6.1 文件上传

Future<void> uploadFile(File file) async { final formData = FormData.fromMap({ 'file': await MultipartFile.fromFile(file.path), 'name': 'test.jpg', }); await dio.post('/upload', data: formData); }

6.2 文件下载

Future<void> downloadFile(String url, String savePath) async { await dio.download( url, savePath, onReceiveProgress: (received, total) { final progress = (received / total * 100).toStringAsFixed(0); print('下载进度: $progress%'); }, ); }

七、实战案例:API服务

7.1 创建API服务类

class ApiService { final Dio _dio; ApiService(this._dio); Future<User> getUser(String id) async { final response = await _dio.get('/users/$id'); return User.fromJson(response.data); } Future<List<User>> getUsers() async { final response = await _dio.get('/users'); return (response.data as List).map((e) => User.fromJson(e)).toList(); } Future<User> createUser(User user) async { final response = await _dio.post('/users', data: user.toJson()); return User.fromJson(response.data); } Future<void> updateUser(String id, User user) async { await _dio.put('/users/$id', data: user.toJson()); } Future<void> deleteUser(String id) async { await _dio.delete('/users/$id'); } }

7.2 依赖注入

// 使用GetIt final getIt = GetIt.instance; void setupLocator() { getIt.registerSingleton<Dio>(Dio( BaseOptions(baseUrl: 'https://api.example.com'), )); getIt.registerSingleton<ApiService>(ApiService(getIt())); }

7.3 配合状态管理

class UserViewModel extends ChangeNotifier { final ApiService _apiService; User? _user; bool _isLoading = false; String? _error; UserViewModel(this._apiService); Future<void> loadUser(String id) async { _isLoading = true; _error = null; notifyListeners(); try { _user = await _apiService.getUser(id); } catch (e) { _error = e.toString(); } _isLoading = false; notifyListeners(); } }

八、性能优化

8.1 请求缓存

final cache = <String, dynamic>{}; Future<T> cachedRequest<T>(String key, Future<T> Function() request) async { if (cache.containsKey(key)) { return cache[key] as T; } final result = await request(); cache[key] = result; return result; }

8.2 请求合并

Future<List<User>> fetchUsers(List<String> ids) async { final futures = ids.map((id) => _apiService.getUser(id)); return await Future.wait(futures); }

8.3 连接池

final dio = Dio(BaseOptions( connectTimeout: const Duration(seconds: 5), receiveTimeout: const Duration(seconds: 3), maxConnectionsPerHost: 5, ));

九、最佳实践

9.1 环境配置

enum Environment { development, staging, production } class Config { static String baseUrl(Environment env) { switch (env) { case Environment.development: return 'https://dev.api.example.com'; case Environment.staging: return 'https://staging.api.example.com'; case Environment.production: return 'https://api.example.com'; } } }

9.2 日志记录

dio.interceptors.add(InterceptorsWrapper( onRequest: (options, handler) { print('请求: ${options.method} ${options.path}'); return handler.next(options); }, ));

9.3 测试网络层

void main() { test('getUser returns user', () async { final dio = Dio(BaseOptions(baseUrl: 'https://api.example.com')); final service = ApiService(dio); final user = await service.getUser('1'); expect(user.id, '1'); }); }

十、总结

Flutter网络请求是应用开发的核心技能,通过合理使用dio库和良好的架构设计,可以构建健壮的网络层。

关键要点:

  • 使用dio进行网络请求
  • 使用拦截器处理请求/响应
  • 实现统一错误处理
  • 支持请求取消和重试
  • 考虑性能优化和缓存

掌握网络请求,将使你的Flutter应用更加稳定和高效。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/22 1:37:08

单片机堆栈溢出怎么排查,面试现场你能答出几步

面试官问&#xff1a;"你们的项目堆栈多大&#xff1f;怎么判断会不会溢出&#xff1f;"你是不是脱口而出"分配大一点就行了"&#xff1f;说实话&#xff0c;这个问题我当年也答得很烂&#xff0c;直到真正踩过坑才发现&#xff0c;堆栈溢出这东西&#xf…

作者头像 李华
网站建设 2026/5/22 1:28:30

光化学烟雾箱搭建全攻略:从选型到出数据的完整指南

前言光化学烟雾箱&#xff08;Photochemical Smog Chamber&#xff09;是大气环境科学研究的核心实验装置&#xff0c;广泛应用于臭氧生成机制、二次有机气溶胶&#xff08;SOA&#xff09;研究、VOCs大气化学反应等领域。近年来&#xff0c;随着国内大气污染防治研究的深入&am…

作者头像 李华
网站建设 2026/5/22 1:28:27

ctf show web入门156

这道题跟前面的题目基本相同不过区别在于在上传木马文件的时候的校验更加严格 这里即使跟上一题一样将php过滤绕过后还是上传失败&#xff0c;说明还有限制我们这里使用二分法寻找哪里存在限制导致我们的文件上传失败&#xff0c;这一步成功上传说明限制在我们去除的那一部分这…

作者头像 李华
网站建设 2026/5/22 1:27:15

windows安装vue-cli

1.安装node.js 到官网https://nodejs.org/en/download下载安装即可&#xff0c;有windows的安装包 2.安装yarn&#xff08;用npm可跳过&#xff09; npm install --global yarn报错&#xff1a; npm : 无法加载文件 C:\Program Files\nodejs\npm.ps1&#xff0c;因为在此系统上…

作者头像 李华
网站建设 2026/5/22 1:24:04

ChatGPT Plus 怎么购买?2026 开通教程

如果你还在犹豫是否有必要开通 Plus&#xff0c;可以先通过AI模型聚合平台 做一些基础体验&#xff0c;对比不同模型在写代码、改文档、做总结时的效果&#xff0c;再决定要不要正式升级 ChatGPT Plus。到了 2026 年&#xff0c;ChatGPT 已经不只是“聊天工具”&#xff0c;更像…

作者头像 李华
网站建设 2026/5/22 1:21:49

2026网盘横评:国民级云盘领衔,这几款备选也值得一看

前言作为长期接触AI资源、代码项目、大文件存储的从业者&#xff0c;日常高频使用各类网盘。很多朋友都会纠结主流网盘该如何选择&#xff0c;不同产品的存储能力、传输表现、功能适配差距明显。本文摒弃夸张测评&#xff0c;以客观分享的视角&#xff0c;从传输、存储、功能、…

作者头像 李华