news 2026/5/11 10:32:20

Flutter Dio 网络请求完全指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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. 封装网络请求服务

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

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

Linux Deadline 调度器的任务出队:dl_dequeue_task 的实现

简介在 Linux 内核调度体系中&#xff0c;SCHED_DEADLINE作为硬实时调度策略&#xff0c;依托EDF 最早截止时间优先与CBS 恒定带宽服务器两大核心算法&#xff0c;承载着工业控制、自动驾驶域控制器、航空航天实时测控、5G 基带处理、专业音视频低延迟编解码等对时间确定性、调…

作者头像 李华
网站建设 2026/5/11 10:23:50

YOLO11部署优化:算子重排与融合 | 详解如何使用ONNX GraphSurgeon精简YOLO11导出模型,剔除冗余节点

引言:从训练到部署,那一道看不见的“坎” 在目标检测领域,一条被无数算法工程师反复验证的铁律是:“训练时刷榜的模型,到了部署环节往往原形毕露。”你在服务器端的V100上跑出80帧的高光时刻,一旦导出ONNX、丢进Jetson Orin NX,帧率可能直接腰斩——甚至更惨。 问题出…

作者头像 李华
网站建设 2026/5/11 10:23:50

Fooocus:3分钟从AI绘画小白到专业创作者的秘密武器

Fooocus&#xff1a;3分钟从AI绘画小白到专业创作者的秘密武器 【免费下载链接】Fooocus Focus on prompting and generating 项目地址: https://gitcode.com/GitHub_Trending/fo/Fooocus 你是否曾经被复杂的AI绘画工具劝退&#xff1f;面对Midjourney的订阅费用、Stabl…

作者头像 李华
网站建设 2026/5/11 10:19:31

打造你的专属桌面伙伴:DyberPet开源桌面宠物框架完全指南

打造你的专属桌面伙伴&#xff1a;DyberPet开源桌面宠物框架完全指南 【免费下载链接】DyberPet Desktop Cyber Pet Framework based on PySide6 项目地址: https://gitcode.com/GitHub_Trending/dy/DyberPet 你是否厌倦了单调的桌面环境&#xff1f;是否希望在繁忙的工…

作者头像 李华
网站建设 2026/5/11 10:16:40

MarkDownload:网页内容转换为Markdown格式的完整解决方案

MarkDownload&#xff1a;网页内容转换为Markdown格式的完整解决方案 【免费下载链接】markdownload A Firefox and Google Chrome extension to clip websites and download them into a readable markdown file. 项目地址: https://gitcode.com/gh_mirrors/ma/markdownload…

作者头像 李华
网站建设 2026/5/11 10:15:37

大语言模型评估指南:从ChatGPT评测看LLM能力边界与挑战

1. 项目概述与背景如果你在过去一年里关注过人工智能&#xff0c;尤其是自然语言处理领域&#xff0c;那么“ChatGPT”这个名字对你来说一定不陌生。从2022年底横空出世&#xff0c;到如今成为科技、教育乃至日常生活中的一个高频词&#xff0c;以ChatGPT为代表的大语言模型&am…

作者头像 李华