Flutter 网络请求完全指南
·
Flutter 网络请求完全指南
引言
网络请求是移动应用开发的核心。本文将深入探讨 Flutter 网络请求的各种方式和最佳实践。
基础概念回顾
HTTP 方法
- GET: 获取资源
- POST: 创建资源
- PUT: 更新资源
- DELETE: 删除资源
- PATCH: 部分更新
状态码
- 2xx: 成功
- 3xx: 重定向
- 4xx: 客户端错误
- 5xx: 服务器错误
常用库
- http: Dart 官方库
- dio: 强大的 HTTP 客户端
- retrofit: 类型安全的 HTTP 客户端
高级技巧一:使用 Dio
基础配置
import 'package:dio/dio.dart';
final dio = Dio(BaseOptions(
baseUrl: 'https://api.example.com',
connectTimeout: const Duration(seconds: 5),
receiveTimeout: const Duration(seconds: 5),
));
GET 请求
Future<User> getUser(String id) async {
try {
final response = await dio.get('/users/$id');
return User.fromJson(response.data);
} catch (e) {
throw Exception('Failed to fetch user');
}
}
POST 请求
Future<User> createUser(User user) async {
try {
final response = await dio.post(
'/users',
data: user.toJson(),
);
return User.fromJson(response.data);
} catch (e) {
throw Exception('Failed to create user');
}
}
拦截器
dio.interceptors.add(InterceptorsWrapper(
onRequest: (options, handler) {
options.headers['Authorization'] = 'Bearer token';
return handler.next(options);
},
onResponse: (response, handler) {
return handler.next(response);
},
onError: (DioException e, handler) {
print('Error: ${e.message}');
return handler.next(e);
},
));
高级技巧二:使用 Retrofit
定义接口
part 'api_service.g.dart';
@RestApi(baseUrl: 'https://api.example.com')
abstract class ApiService {
factory ApiService(Dio dio, {String baseUrl}) = _ApiService;
@GET('/users')
Future<List<User>> getUsers();
@GET('/users/{id}')
Future<User> getUser(@Path('id') String id);
@POST('/users')
Future<User> createUser(@Body() User user);
@PUT('/users/{id}')
Future<User> updateUser(
@Path('id') String id,
@Body() User user,
);
@DELETE('/users/{id}')
Future<void> deleteUser(@Path('id') String id);
}
生成代码
flutter pub run build_runner build
使用服务
final dio = Dio();
final apiService = ApiService(dio);
final users = await apiService.getUsers();
final user = await apiService.getUser('1');
高级技巧三:错误处理
自定义异常
class ApiException implements Exception {
final int? statusCode;
final String message;
ApiException({this.statusCode, required this.message});
@override
String toString() => 'ApiException: $statusCode - $message';
}
统一错误处理
Future<T> handleApiCall<T>(Future<T> Function() call) async {
try {
return await call();
} on DioException catch (e) {
if (e.response != null) {
throw ApiException(
statusCode: e.response!.statusCode,
message: e.response!.data['message'] ?? 'Unknown error',
);
} else {
throw ApiException(
message: e.message ?? 'Network error',
);
}
} catch (e) {
throw ApiException(message: e.toString());
}
}
// 使用
final user = await handleApiCall(() => apiService.getUser('1'));
高级技巧四:请求取消
CancelToken cancelToken = CancelToken();
dio.get(
'/users',
cancelToken: cancelToken,
);
// 取消请求
cancelToken.cancel('Request cancelled');
实战案例:完整 API 服务
class ApiService {
final Dio _dio;
ApiService() : _dio = Dio(BaseOptions(
baseUrl: 'https://api.example.com',
headers: {'Accept': 'application/json'},
)) {
_setupInterceptors();
}
void _setupInterceptors() {
_dio.interceptors.add(InterceptorsWrapper(
onRequest: (options, handler) {
final token = _getToken();
if (token != null) {
options.headers['Authorization'] = 'Bearer $token';
}
handler.next(options);
},
onResponse: (response, handler) {
handler.next(response);
},
onError: (e, handler) {
if (e.response?.statusCode == 401) {
_handleUnauthorized();
}
handler.next(e);
},
));
}
Future<User> getUser(String id) async {
final response = await _dio.get('/users/$id');
return User.fromJson(response.data);
}
Future<List<User>> getUsers({int page = 1, int limit = 10}) async {
final response = await _dio.get(
'/users',
queryParameters: {'page': page, 'limit': limit},
);
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> deleteUser(String id) async {
await _dio.delete('/users/$id');
}
String? _getToken() {
// 从存储获取 token
return 'user_token';
}
void _handleUnauthorized() {
// 处理未授权
}
}
实战案例:网络状态管理
enum NetworkStatus { loading, success, error, initial }
class NetworkState<T> {
final NetworkStatus status;
final T? data;
final String? errorMessage;
const NetworkState._({
required this.status,
this.data,
this.errorMessage,
});
const NetworkState.loading() : this._(status: NetworkStatus.loading);
const NetworkState.success(T data) : this._(status: NetworkStatus.success, data: data);
const NetworkState.error(String message) : this._(status: NetworkStatus.error, errorMessage: message);
const NetworkState.initial() : this._(status: NetworkStatus.initial);
}
实战案例:带缓存的请求
class CachedApiService {
final ApiService _apiService;
final Map<String, dynamic> _cache = {};
final Duration _cacheDuration = const Duration(minutes: 5);
final Map<String, DateTime> _cacheTimestamps = {};
CachedApiService(this._apiService);
Future<T> getWithCache<T>(
String key,
Future<T> Function() fetchFunction,
) async {
if (_isCacheValid(key)) {
return _cache[key] as T;
}
final result = await fetchFunction();
_cache[key] = result;
_cacheTimestamps[key] = DateTime.now();
return result;
}
bool _isCacheValid(String key) {
final timestamp = _cacheTimestamps[key];
if (timestamp == null) return false;
return DateTime.now().difference(timestamp) < _cacheDuration;
}
void clearCache() {
_cache.clear();
_cacheTimestamps.clear();
}
}
常见问题与解决方案
Q1:请求超时?
A:设置超时时间:
Dio(BaseOptions(
connectTimeout: const Duration(seconds: 10),
receiveTimeout: const Duration(seconds: 10),
))
Q2:认证失败?
A:添加拦截器:
dio.interceptors.add(InterceptorsWrapper(
onRequest: (options, handler) {
options.headers['Authorization'] = 'Bearer token';
handler.next(options);
},
));
Q3:网络错误?
A:处理 DioException:
try {
final response = await dio.get('/users');
} on DioException catch (e) {
if (e.type == DioExceptionType.connectionError) {
// 网络错误
}
}
最佳实践
1. 使用单例模式
class ApiService {
static final ApiService _instance = ApiService._internal();
factory ApiService() => _instance;
ApiService._internal() {
// 初始化
}
}
2. 分离 API 层
// 数据层
class UserRepository {
final ApiService _apiService;
Future<User> getUser(String id) {
return _apiService.getUser(id);
}
}
3. 使用模型类
class User {
final String id;
final String name;
User({required this.id, required this.name});
factory User.fromJson(Map<String, dynamic> json) {
return User(
id: json['id'],
name: json['name'],
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
};
}
}
总结
Flutter 网络请求是构建数据驱动应用的核心。通过本文的学习,你应该能够:
- 使用 Dio 进行网络请求
- 使用 Retrofit 实现类型安全
- 处理错误和异常
- 取消请求
- 实现缓存机制
- 管理网络状态
掌握这些技巧,能够帮助你构建更加稳定和可靠的应用。
更多推荐
所有评论(0)