当前位置: 首页 > news >正文

Flutter Dio 网络请求完全指南

Flutter Dio 网络请求完全指南

引言

Dio 是 Flutter 中最流行的网络请求库,它提供了强大的 HTTP 客户端功能。本文将深入探讨 Dio 的各种用法和高级技巧。

基础概念回顾

Dio 特性

  1. 支持多种请求方法- GET, POST, PUT, DELETE, PATCH, HEAD
  2. 拦截器- 请求/响应拦截
  3. 请求取消- 支持取消请求
  4. 超时配置- 连接超时、接收超时
  5. FormData- 支持表单数据
  6. 文件上传/下载- 支持进度监听

基本用法

import 'package:dio/dio.dart'; final dio = Dio(); // GET 请求 Response response = await dio.get('https://api.example.com/data'); // POST 请求 Response response = await dio.post('https://api.example.com/data', data: { 'name': 'John', 'age': 30, });

高级技巧一:配置 Dio

基础配置

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

自定义配置

dio.options.baseUrl = 'https://api.example.com'; dio.options.connectTimeout = const Duration(seconds: 10); dio.options.receiveTimeout = const Duration(seconds: 5);

高级技巧二:拦截器

请求拦截器

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

响应拦截器

dio.interceptors.add(InterceptorsWrapper( onResponse: (response, handler) { if (response.statusCode == 200) { return handler.next(response); } else { return handler.reject(DioException( requestOptions: response.requestOptions, response: response, )); } }, ));

错误拦截器

dio.interceptors.add(InterceptorsWrapper( onError: (DioException e, handler) { if (e.response?.statusCode == 401) { // 处理未授权 } return handler.reject(e); }, ));

日志拦截器

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

高级技巧三:请求取消

单个请求取消

CancelToken cancelToken = CancelToken(); dio.get( 'https://api.example.com/data', cancelToken: cancelToken, ); // 取消请求 cancelToken.cancel('取消请求');

多个请求取消

CancelToken cancelToken = CancelToken(); dio.get('url1', cancelToken: cancelToken); dio.get('url2', cancelToken: cancelToken); dio.get('url3', cancelToken: cancelToken); // 取消所有请求 cancelToken.cancel('全部取消');

高级技巧四:文件上传

单个文件上传

FormData formData = FormData.fromMap({ 'file': await MultipartFile.fromFile( '/path/to/file.jpg', filename: 'photo.jpg', ), }); Response response = await dio.post( '/upload', data: formData, );

多个文件上传

FormData formData = FormData.fromMap({ 'files': [ await MultipartFile.fromFile('/path/to/file1.jpg'), await MultipartFile.fromFile('/path/to/file2.jpg'), ], }); Response response = await dio.post('/upload', data: formData);

上传进度监听

Response response = await dio.post( '/upload', data: formData, onSendProgress: (int sent, int total) { print('上传进度: ${(sent / total * 100).toStringAsFixed(0)}%'); }, );

高级技巧五:文件下载

基本下载

await dio.download( 'https://example.com/file.pdf', '/path/to/save/file.pdf', );

下载进度监听

await dio.download( 'https://example.com/file.pdf', '/path/to/save/file.pdf', onReceiveProgress: (int received, int total) { print('下载进度: ${(received / total * 100).toStringAsFixed(0)}%'); }, );

断点续传

await dio.download( 'https://example.com/file.pdf', '/path/to/save/file.pdf', options: Options( headers: {'Range': 'bytes=1024-'}, ), );

高级技巧六:并发请求

并发多个请求

Future<void> fetchData() async { final futures = [ dio.get('/users'), dio.get('/posts'), dio.get('/comments'), ]; final results = await Future.wait(futures); final users = results[0].data; final posts = results[1].data; final comments = results[2].data; }

带超时的并发请求

Future<void> fetchWithTimeout() async { try { final result = await Future.any([ dio.get('/data').timeout(const Duration(seconds: 5)), Future.delayed(const Duration(seconds: 3)).then((_) => throw TimeoutException()), ]); } on TimeoutException { // 超时处理 } }

实战案例:封装网络请求

创建 ApiService

class ApiService { late Dio _dio; ApiService() { _dio = Dio(BaseOptions( baseUrl: 'https://api.example.com', connectTimeout: const Duration(seconds: 10), receiveTimeout: const Duration(seconds: 5), )); _setupInterceptors(); } void _setupInterceptors() { _dio.interceptors.add(LogInterceptor( requestBody: true, responseBody: true, )); _dio.interceptors.add(InterceptorsWrapper( onRequest: (options, handler) { final token = _getToken(); if (token != null) { options.headers['Authorization'] = 'Bearer $token'; } return handler.next(options); }, onError: (e, handler) { if (e.response?.statusCode == 401) { _handleUnauthorized(); } return handler.reject(e); }, )); } String? _getToken() { // 从存储获取 token return 'user_token'; } void _handleUnauthorized() { // 处理未授权 } Future<User> getUser(int 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(int id, User user) async { await _dio.put('/users/$id', data: user.toJson()); } Future<void> deleteUser(int id) async { await _dio.delete('/users/$id'); } }

使用 ApiService

final apiService = ApiService(); // 获取用户 final user = await apiService.getUser(1); // 获取用户列表 final users = await apiService.getUsers(); // 创建用户 final newUser = await apiService.createUser(User(name: 'John')); // 更新用户 await apiService.updateUser(1, User(name: 'John Updated')); // 删除用户 await apiService.deleteUser(1);

实战案例:错误处理

自定义异常

enum ApiErrorType { network, unauthorized, notFound, server, unknown, } class ApiException implements Exception { final ApiErrorType type; final String message; final int? statusCode; ApiException({ required this.type, required this.message, this.statusCode, }); }

错误处理服务

class ErrorHandler { static ApiException handleError(DioException e) { if (e.type == DioExceptionType.connectionError) { return ApiException( type: ApiErrorType.network, message: '网络连接失败', ); } if (e.type == DioExceptionType.receiveTimeout) { return ApiException( type: ApiErrorType.network, message: '请求超时', ); } final statusCode = e.response?.statusCode; if (statusCode == 401) { return ApiException( type: ApiErrorType.unauthorized, message: '未授权,请重新登录', statusCode: 401, ); } if (statusCode == 404) { return ApiException( type: ApiErrorType.notFound, message: '资源未找到', statusCode: 404, ); } if (statusCode != null && statusCode >= 500) { return ApiException( type: ApiErrorType.server, message: '服务器错误', statusCode: statusCode, ); } return ApiException( type: ApiErrorType.unknown, message: '未知错误', ); } }

使用错误处理

try { final user = await apiService.getUser(1); } on DioException catch (e) { final error = ErrorHandler.handleError(e); switch (error.type) { case ApiErrorType.network: // 显示网络错误 break; case ApiErrorType.unauthorized: // 跳转到登录页 break; case ApiErrorType.notFound: // 显示资源未找到 break; case ApiErrorType.server: // 显示服务器错误 break; case ApiErrorType.unknown: // 显示未知错误 break; } }

实战案例:缓存策略

缓存拦截器

class CacheInterceptor extends Interceptor { final Map<String, Response> _cache = {}; @override void onRequest(RequestOptions options, RequestInterceptorHandler handler) { if (options.method == 'GET') { final cached = _cache[options.path]; if (cached != null) { return handler.resolve(cached); } } return handler.next(options); } @override void onResponse(Response response, ResponseInterceptorHandler handler) { if (response.requestOptions.method == 'GET') { _cache[response.requestOptions.path] = response; } return handler.next(response); } void clearCache() { _cache.clear(); } void removeCache(String path) { _cache.remove(path); } }

使用缓存拦截器

dio.interceptors.add(CacheInterceptor());

常见问题与解决方案

Q1:如何处理 SSL 证书问题?

A:配置 HttpClientAdapter:

dio.httpClientAdapter = Http2Adapter( ConnectionManager( idleTimeout: 10000, onClientCreate: (_, config) { config.onBadCertificate = (certificate, host, port) => true; }, ), );

Q2:如何设置代理?

A:配置代理:

(dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (client) { client.findProxy = (uri) { return 'PROXY proxy.example.com:8888'; }; };

Q3:如何处理大文件下载?

A:使用流下载:

final response = await dio.get( 'https://example.com/large_file.zip', options: Options(responseType: ResponseType.stream), ); final file = File('/path/to/save.zip'); final sink = file.openWrite(); await sink.addStream(response.data.stream); await sink.close();

最佳实践

1. 封装 Dio 实例

// 推荐:封装到服务类 final apiService = ApiService(); // 不推荐:直接使用 Dio final dio = Dio();

2. 使用 Interceptors

// 推荐:使用拦截器统一处理 dio.interceptors.add(InterceptorsWrapper( onRequest: (options, handler) { options.headers['Authorization'] = 'Bearer token'; return handler.next(options); }, ));

3. 错误处理

// 推荐:统一错误处理 try { final response = await dio.get('/data'); } on DioException catch (e) { // 处理错误 }

总结

Dio 是 Flutter 中功能强大的网络请求库。通过本文的学习,你应该能够:

  1. 配置 Dio 实例
  2. 使用拦截器处理请求/响应
  3. 实现文件上传和下载
  4. 处理并发请求
  5. 封装网络请求服务

掌握这些技巧,能够帮助你构建更加健壮的网络层。

http://www.jsqmd.com/news/795229/

相关文章:

  • 技术如何体现人文关怀:从医疗健康领域的范式转变看工程师思维转型
  • OBS多平台直播终极指南:如何一键同步推流到所有主流平台
  • 2026年无锡整木定制深度选购指南|风佳整木定制官方联系通道 - 优质企业观察收录
  • 开发者云服务选型指南:从VPS到Serverless的性价比决策
  • System Cursor:基于多模态AI的系统级上下文感知补全工具实践
  • 原子力显微镜环境振动控制与精密仪器迁移实践
  • 你的桌面需要一个会思考的伙伴吗?DyberPet让虚拟宠物拥有情感与智慧
  • MarkDownload:网页内容结构化保存的技术方案
  • Spring Boot API 文档与 OpenAPI 集成最佳实践
  • 2026年济宁GEO优化服务商推荐top5 本地企业选型专业参考指南 - 产业观察网
  • iOS激活锁终极绕过指南:开源工具applera1n的完整解决方案
  • 智读致用|山田智惠《复盘自己》:复盘不是反思错误,而是发现你早已拥有的财富
  • 当大模型认不出一个具体名字:MiniMax 回答失灵,问题未必只在模型本身
  • 线上回收盒马鲜生卡靠谱吗?最全回收指南告诉你! - 团团收购物卡回收
  • PvZ Toolkit终极指南:免费植物大战僵尸修改器完整使用教程
  • 护发精油品牌排行榜:4个口碑与实力并存的品牌 - 速递信息
  • 2026AI幻觉深度研究报告
  • 如何快速掌握英雄联盟智能BP助手:面向新手的完整指南
  • 还在为排位赛BP头疼吗?让Seraphine帮你做决策
  • ARM架构TLB机制与地址转换优化实践
  • 2026最新中央供水系统厂家推荐!国内优质权威榜单发布,性能稳定上海等地厂家实力出众 - 十大品牌榜
  • 电梯轿厢不锈钢装饰板选材、镀色稳定性与声学安装全解析 - 博客万
  • TransNet V2 终极指南:快速掌握视频镜头边界检测技术
  • PyTorch转ONNX时,如何正确设置动态输入尺寸(以RetinaFace多输出为例)
  • 基于Nuxt 3与AI大模型的ATS简历智能匹配系统开发实战
  • 2026年中山五金制品工程采购指南:5大品牌横评与选购攻略 - 优质企业观察收录
  • 2026年5月榜单:气体检测仪生产商排名及价格区间参考 - 品牌推荐大师
  • 金价暴跌前夜!兰州人速选福正美变现 - 福正美黄金回收
  • 2026大理婚纱照全维度深度测评|避坑指南+全国备婚新人优选推荐 - 深度智识库
  • Linux Deadline 调度器的 pick_next_task:EDF 任务选择