Flutter网络请求高级技巧
·
Flutter网络请求高级技巧
核心概念
网络请求基础
Flutter中常用的网络请求库包括http和dio。http是Flutter官方提供的基础网络请求库,而dio是一个功能更强大的第三方网络请求库。
HTTP方法
- GET:获取资源
- POST:创建资源
- PUT:更新资源
- DELETE:删除资源
- PATCH:部分更新资源
高级技巧
使用dio库
import 'package:dio/dio.dart';
// 创建dio实例
final dio = Dio();
// 基本GET请求
Future<void> getRequest() async {
try {
final response = await dio.get('https://api.example.com/users');
print(response.data);
} catch (e) {
print(e);
}
}
// 基本POST请求
Future<void> postRequest() async {
try {
final response = await dio.post('https://api.example.com/users', data: {
'name': 'John Doe',
'email': 'john@example.com'
});
print(response.data);
} catch (e) {
print(e);
}
}
拦截器
// 添加请求拦截器
dio.interceptors.add(InterceptorsWrapper(
onRequest: (options, handler) {
// 在发送请求之前做一些处理
print('请求路径: ${options.path}');
print('请求方法: ${options.method}');
print('请求参数: ${options.data}');
// 添加请求头
options.headers['Authorization'] = 'Bearer token';
return handler.next(options);
},
onResponse: (response, handler) {
// 在收到响应后做一些处理
print('响应状态码: ${response.statusCode}');
print('响应数据: ${response.data}');
return handler.next(response);
},
onError: (DioError e, handler) {
// 处理错误
print('错误信息: ${e.message}');
print('错误响应: ${e.response?.data}');
return handler.next(e);
},
));
错误处理
Future<void> handleError() async {
try {
final response = await dio.get('https://api.example.com/users');
print(response.data);
} on DioError catch (e) {
if (e.response != null) {
// 服务器返回错误
print('状态码: ${e.response?.statusCode}');
print('错误数据: ${e.response?.data}');
switch (e.response?.statusCode) {
case 400:
print('请求参数错误');
break;
case 401:
print('未授权,请重新登录');
break;
case 403:
print('拒绝访问');
break;
case 404:
print('资源不存在');
break;
case 500:
print('服务器内部错误');
break;
default:
print('未知错误');
}
} else {
// 网络错误
print('网络错误: ${e.message}');
}
} catch (e) {
print('其他错误: $e');
}
}
超时设置
// 设置全局超时
dio.options = BaseOptions(
connectTimeout: Duration(seconds: 10),
receiveTimeout: Duration(seconds: 10),
sendTimeout: Duration(seconds: 10),
);
// 为单个请求设置超时
Future<void> requestWithTimeout() async {
try {
final response = await dio.get(
'https://api.example.com/users',
options: Options(
connectTimeout: Duration(seconds: 5),
receiveTimeout: Duration(seconds: 5),
),
);
print(response.data);
} catch (e) {
print(e);
}
}
缓存策略
// 使用 dio_cache_interceptor 库
import 'package:dio_cache_interceptor/dio_cache_interceptor.dart';
import 'package:dio_cache_interceptor_hive_store/dio_cache_interceptor_hive_store.dart';
import 'package:path_provider/path_provider.dart';
Future<void> setupCache() async {
// 获取缓存目录
final dir = await getTemporaryDirectory();
final cacheStore = HiveCacheStore(dir.path);
// 配置缓存选项
final cacheOptions = CacheOptions(
store: cacheStore,
policy: CachePolicy.request, // 缓存策略
hitCacheOnErrorExcept: [401, 403], // 错误时缓存
maxStale: Duration(days: 7), // 最大缓存时间
);
// 创建带缓存的 dio 实例
final dio = Dio()..interceptors.add(DioCacheInterceptor(options: cacheOptions));
// 使用缓存请求
final response = await dio.get('https://api.example.com/users');
print(response.data);
}
文件上传
// 上传单个文件
Future<void> uploadFile() async {
try {
final formData = FormData.fromMap({
'name': 'John Doe',
'file': await MultipartFile.fromFile('path/to/file.jpg', filename: 'file.jpg'),
});
final response = await dio.post('https://api.example.com/upload', data: formData);
print(response.data);
} catch (e) {
print(e);
}
}
// 上传多个文件
Future<void> uploadMultipleFiles() async {
try {
final formData = FormData.fromMap({
'name': 'John Doe',
'files': [
await MultipartFile.fromFile('path/to/file1.jpg', filename: 'file1.jpg'),
await MultipartFile.fromFile('path/to/file2.jpg', filename: 'file2.jpg'),
],
});
final response = await dio.post('https://api.example.com/upload', data: formData);
print(response.data);
} catch (e) {
print(e);
}
}
// 上传进度
Future<void> uploadWithProgress() async {
try {
final formData = FormData.fromMap({
'file': await MultipartFile.fromFile('path/to/file.jpg', filename: 'file.jpg'),
});
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);
}
}
文件下载
// 基本下载
Future<void> downloadFile() async {
try {
final response = await dio.download(
'https://example.com/file.jpg',
'path/to/save/file.jpg',
);
print('下载完成');
} catch (e) {
print(e);
}
}
// 下载进度
Future<void> downloadWithProgress() async {
try {
final response = await dio.download(
'https://example.com/file.jpg',
'path/to/save/file.jpg',
onReceiveProgress: (int received, int total) {
print('下载进度: ${(received / total * 100).toStringAsFixed(0)}%');
},
);
print('下载完成');
} catch (e) {
print(e);
}
}
// 断点续传
Future<void> resumeDownload() async {
try {
// 检查文件是否已存在
final file = File('path/to/save/file.jpg');
final fileLength = file.existsSync() ? file.lengthSync() : 0;
final response = await dio.download(
'https://example.com/file.jpg',
'path/to/save/file.jpg',
options: Options(
headers: {'Range': 'bytes=$fileLength-'}, // 设置 Range 请求头
),
onReceiveProgress: (int received, int total) {
final actualReceived = received + fileLength;
final actualTotal = total + fileLength;
print('下载进度: ${(actualReceived / actualTotal * 100).toStringAsFixed(0)}%');
},
);
print('下载完成');
} catch (e) {
print(e);
}
}
最佳实践
网络状态管理
import 'package:connectivity_plus/connectivity_plus.dart';
// 检查网络状态
Future<void> checkNetworkStatus() async {
final connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.none) {
print('无网络连接');
} else if (connectivityResult == ConnectivityResult.mobile) {
print('移动网络');
} else if (connectivityResult == ConnectivityResult.wifi) {
print('WiFi网络');
}
}
// 监听网络状态变化
void listenNetworkChanges() {
Connectivity().onConnectivityChanged.listen((ConnectivityResult result) {
if (result == ConnectivityResult.none) {
print('无网络连接');
} else if (result == ConnectivityResult.mobile) {
print('移动网络');
} else if (result == ConnectivityResult.wifi) {
print('WiFi网络');
}
});
}
响应模型
// 定义响应模型
class User {
final int id;
final String name;
final String email;
User({required this.id, required this.name, required this.email});
factory User.fromJson(Map<String, dynamic> json) {
return User(
id: json['id'],
name: json['name'],
email: json['email'],
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
'email': email,
};
}
}
// 使用响应模型
Future<void> getUser() async {
try {
final response = await dio.get('https://api.example.com/users/1');
final user = User.fromJson(response.data);
print('用户: ${user.name}');
} catch (e) {
print(e);
}
}
网络请求封装
// 网络请求封装类
class ApiService {
final Dio _dio;
ApiService() : _dio = Dio() {
// 配置基础选项
_dio.options = BaseOptions(
baseUrl: 'https://api.example.com',
connectTimeout: Duration(seconds: 10),
receiveTimeout: Duration(seconds: 10),
);
// 添加拦截器
_dio.interceptors.add(InterceptorsWrapper(
onRequest: (options, handler) {
// 添加认证token
final token = getToken();
if (token != null) {
options.headers['Authorization'] = 'Bearer $token';
}
return handler.next(options);
},
onError: (DioError e, handler) {
// 处理401错误(未授权)
if (e.response?.statusCode == 401) {
// 跳转到登录页
// Navigator.pushReplacementNamed(context, '/login');
}
return handler.next(e);
},
));
}
String? getToken() {
// 从本地存储获取token
// 这里简化处理,实际应该使用shared_preferences或其他存储方案
return 'your-token';
}
// GET请求
Future<T> get<T>(String path, {Map<String, dynamic>? queryParameters, Options? options}) async {
final response = await _dio.get(path, queryParameters: queryParameters, options: options);
return response.data as T;
}
// POST请求
Future<T> post<T>(String path, {dynamic data, Options? options}) async {
final response = await _dio.post(path, data: data, options: options);
return response.data as T;
}
// PUT请求
Future<T> put<T>(String path, {dynamic data, Options? options}) async {
final response = await _dio.put(path, data: data, options: options);
return response.data as T;
}
// DELETE请求
Future<T> delete<T>(String path, {Options? options}) async {
final response = await _dio.delete(path, options: options);
return response.data as T;
}
// 上传文件
Future<T> upload<T>(String path, FormData formData, {void Function(int, int)? onSendProgress}) async {
final response = await _dio.post(path, data: formData, onSendProgress: onSendProgress);
return response.data as T;
}
// 下载文件
Future<void> download(String url, String savePath, {void Function(int, int)? onReceiveProgress}) async {
await _dio.download(url, savePath, onReceiveProgress: onReceiveProgress);
}
}
// 使用示例
void main() async {
final apiService = ApiService();
// GET请求
final users = await apiService.get<List<dynamic>>('/users');
print(users);
// POST请求
final user = await apiService.post<Map<String, dynamic>>('/users', data: {
'name': 'John Doe',
'email': 'john@example.com'
});
print(user);
}
重试机制
// 重试机制
Future<T> retry<T>(Future<T> Function() fn, {int retryCount = 3, Duration delay = const Duration(seconds: 1)}) async {
try {
return await fn();
} catch (e) {
if (retryCount > 0) {
print('请求失败,正在重试... ($retryCount)');
await Future.delayed(delay);
return retry(fn, retryCount: retryCount - 1, delay: delay);
} else {
rethrow;
}
}
}
// 使用重试机制
Future<void> fetchDataWithRetry() async {
try {
final response = await retry(() => dio.get('https://api.example.com/users'));
print(response.data);
} catch (e) {
print('请求失败: $e');
}
}
实用案例
完整的网络请求示例
import 'package:dio/dio.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/material.dart';
// 网络请求服务
class NetworkService {
static final NetworkService _instance = NetworkService._internal();
factory NetworkService() => _instance;
NetworkService._internal();
final Dio _dio = Dio();
final Connectivity _connectivity = Connectivity();
void init() {
// 配置基础选项
_dio.options = BaseOptions(
baseUrl: 'https://api.example.com',
connectTimeout: Duration(seconds: 10),
receiveTimeout: Duration(seconds: 10),
);
// 添加拦截器
_dio.interceptors.add(InterceptorsWrapper(
onRequest: (options, handler) {
print('请求: ${options.path}');
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);
},
));
}
// 检查网络连接
Future<bool> isConnected() async {
final result = await _connectivity.checkConnectivity();
return result != ConnectivityResult.none;
}
// GET请求
Future<T> get<T>(String path, {Map<String, dynamic>? queryParameters}) async {
if (!await isConnected()) {
throw Exception('无网络连接');
}
final response = await _dio.get(path, queryParameters: queryParameters);
return response.data as T;
}
// POST请求
Future<T> post<T>(String path, {dynamic data}) async {
if (!await isConnected()) {
throw Exception('无网络连接');
}
final response = await _dio.post(path, data: data);
return response.data as T;
}
}
// 数据模型
class User {
final int id;
final String name;
final String email;
User({required this.id, required this.name, required this.email});
factory User.fromJson(Map<String, dynamic> json) {
return User(
id: json['id'],
name: json['name'],
email: json['email'],
);
}
}
// 数据仓库
class UserRepository {
final NetworkService _networkService = NetworkService();
Future<List<User>> getUsers() async {
final data = await _networkService.get<List<dynamic>>('/users');
return data.map((item) => User.fromJson(item)).toList();
}
Future<User> getUser(int id) async {
final data = await _networkService.get<Map<String, dynamic>>('/users/$id');
return User.fromJson(data);
}
Future<User> createUser(User user) async {
final data = await _networkService.post<Map<String, dynamic>>('/users', data: user.toJson());
return User.fromJson(data);
}
}
// 使用示例
void main() async {
// 初始化网络服务
NetworkService().init();
// 创建用户仓库
final userRepository = UserRepository();
try {
// 获取用户列表
final users = await userRepository.getUsers();
print('用户列表: ${users.map((user) => user.name).toList()}');
// 获取单个用户
final user = await userRepository.getUser(1);
print('用户: ${user.name}');
// 创建用户
final newUser = User(id: 0, name: 'John Doe', email: 'john@example.com');
final createdUser = await userRepository.createUser(newUser);
print('创建的用户: ${createdUser.name}');
} catch (e) {
print('错误: $e');
}
}
网络请求状态管理
import 'package:flutter/material.dart';
// 网络请求状态
enum RequestStatus {
initial,
loading,
success,
error,
}
// 网络请求状态管理
class RequestState<T> {
final RequestStatus status;
final T? data;
final String? error;
RequestState({
required this.status,
this.data,
this.error,
});
factory RequestState.initial() {
return RequestState(status: RequestStatus.initial);
}
factory RequestState.loading() {
return RequestState(status: RequestStatus.loading);
}
factory RequestState.success(T data) {
return RequestState(status: RequestStatus.success, data: data);
}
factory RequestState.error(String error) {
return RequestState(status: RequestStatus.error, error: error);
}
}
// 使用示例
class UserListScreen extends StatefulWidget {
@override
_UserListScreenState createState() => _UserListScreenState();
}
class _UserListScreenState extends State<UserListScreen> {
final UserRepository _userRepository = UserRepository();
RequestState<List<User>> _state = RequestState.initial();
@override
void initState() {
super.initState();
fetchUsers();
}
Future<void> fetchUsers() async {
setState(() {
_state = RequestState.loading();
});
try {
final users = await _userRepository.getUsers();
setState(() {
_state = RequestState.success(users);
});
} catch (e) {
setState(() {
_state = RequestState.error(e.toString());
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('用户列表')),
body: Center(
child: _state.status == RequestStatus.loading
? CircularProgressIndicator()
: _state.status == RequestStatus.error
? Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('错误: ${_state.error}'),
ElevatedButton(
onPressed: fetchUsers,
child: Text('重试'),
),
],
)
: _state.status == RequestStatus.success
? ListView.builder(
itemCount: _state.data!.length,
itemBuilder: (context, index) {
final user = _state.data![index];
return ListTile(
title: Text(user.name),
subtitle: Text(user.email),
);
},
)
: SizedBox(),
),
);
}
}
总结
Flutter网络请求是应用开发中的重要组成部分,通过掌握这些高级技巧,你可以创建更加健壮、高效的网络请求系统。
关键要点
- 选择合适的库:根据需求选择
http或dio库。 - 使用拦截器:处理请求头、响应数据和错误。
- 错误处理:妥善处理各种网络错误。
- 超时设置:合理设置超时时间,避免请求无响应。
- 缓存策略:使用缓存提高性能和用户体验。
- 文件上传下载:支持文件的上传和下载,包括进度监听。
- 网络状态管理:检查和监听网络状态。
- 响应模型:使用强类型的响应模型,提高代码可维护性。
- 网络请求封装:封装网络请求,提高代码复用性。
- 重试机制:处理临时网络问题,提高请求成功率。
通过掌握这些高级技巧,你可以创建更加可靠、高效的网络请求系统,提升你的Flutter应用的用户体验。
更多推荐
所有评论(0)