作为一名 iOS 开发者转向 Flutter,你可能会对网络请求的处理方式感到困惑。在 iOS 中,我们习惯使用 URLSession
或 Alamofire
,而在 Flutter 中,我们有了更强大的组合:Dio + Retrofit。
这篇文章将带你深入了解这两个库,并展示它们如何让 Flutter 的网络请求变得简单而强大。
Dio 是一个强大的 Dart HTTP 客户端,它基于 Dart 的 http
包,但提供了更多高级功能。如果你熟悉 iOS 的 Alamofire,那么 Dio 就是 Flutter 世界中的 Alamofire。
import 'package:dio/dio.dart';
void main() async {
// 创建 Dio 实例
final dio = Dio();
// 基础 GET 请求
try {
final response = await dio.get('https://api.example.com/users');
print('Response: ${response.data}');
} catch (e) {
print('Error: $e');
}
// POST 请求
try {
final response = await dio.post(
'https://api.example.com/users',
data: {
'name': 'John Doe',
'email': '[email protected]'
},
);
print('Created user: ${response.data}');
} catch (e) {
print('Error: $e');
}
}
final dio = Dio(BaseOptions(
baseUrl: 'https://api.example.com',
connectTimeout: Duration(seconds: 5),
receiveTimeout: Duration(seconds: 3),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
));
拦截器是 Dio 最强大的功能之一,类似于 iOS 中的 URLSession 代理:
// 请求拦截器
dio.interceptors.add(InterceptorsWrapper(
onRequest: (options, handler) {
// 在请求发送前添加 token
options.headers['Authorization'] = 'Bearer $token';
print('Request: ${options.method} ${options.path}');
handler.next(options);
},
onResponse: (response, handler) {
// 处理响应
print('Response: ${response.statusCode}');
handler.next(response);
},
onError: (error, handler) {
// 处理错误
print('Error: ${error.message}');
handler.next(error);
},
));
Retrofit 是一个代码生成库,它让你可以用注解的方式定义 API 接口,然后自动生成实现代码。如果你熟悉 iOS 的 Moya,那么 Retrofit 就是 Flutter 中的 Moya。
首先在 pubspec.yaml
中添加依赖:
dependencies:
dio: ^5.0.0
retrofit: ^4.0.0
dev_dependencies:
retrofit_generator: ^7.0.0
build_runner: ^2.4.0
import 'package:dio/dio.dart';
import 'package:retrofit/retrofit.dart';
part 'user_api.g.dart';
()
abstract class UserApi {
factory UserApi(Dio dio, {String? baseUrl}) = _UserApi;
('/users')
Future<List<User>> getUsers();
('/users/{id}')
Future<User> getUser(('id') int id);
('/users')
Future<User> createUser(() User user);
('/users/{id}')
Future<User> updateUser(
('id') int id,
() User user,
);
('/users/{id}')
Future<void> deleteUser(('id') int id);
}
('/users') // GET 请求
('/users') // POST 请求
('/users/{id}') // PUT 请求
('/users/{id}') // DELETE 请求
('id') int id // URL 路径参数
('page') int page // 查询参数
() User user // 请求体
('name') String name // 表单字段
('Authorization') String token // 请求头
运行以下命令生成实现代码:
flutter packages pub run build_runner build
这会生成 user_api.g.dart
文件,包含所有接口的具体实现。
// api_service.dart
import 'package:dio/dio.dart';
import 'package:retrofit/retrofit.dart';
part 'api_service.g.dart';
()
abstract class ApiService {
factory ApiService(Dio dio, {String? baseUrl}) = _ApiService;
// 用户相关
('/users/profile')
Future<User> getProfile();
('/users/profile')
Future<User> updateProfile(() User user);
// 动态相关
('/moments')
Future<List<Moment>> getMoments({
('page') int page = 1,
('limit') int limit = 20,
});
('/moments')
Future<Moment> createMoment(() CreateMomentRequest request);
// 文件上传
('/upload')
()
Future<UploadResponse> uploadFile(() File file);
}
// dio_config.dart
class DioConfig {
static Dio createDio() {
final dio = Dio(BaseOptions(
baseUrl: 'https://api.example.com',
connectTimeout: Duration(seconds: 10),
receiveTimeout: Duration(seconds: 10),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
));
// 添加拦截器
dio.interceptors.addAll([
_AuthInterceptor(),
_LoggingInterceptor(),
_ErrorInterceptor(),
]);
return dio;
}
}
class _AuthInterceptor extends Interceptor {
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
// 添加认证 token
final token = getStoredToken();
if (token != null) {
options.headers['Authorization'] = 'Bearer $token';
}
handler.next(options);
}
}
// user_repository.dart
class UserRepository {
final ApiService _apiService;
UserRepository() : _apiService = ApiService(DioConfig.createDio());
Future<User> getProfile() async {
try {
return await _apiService.getProfile();
} catch (e) {
throw UserException('获取用户信息失败: $e');
}
}
Future<User> updateProfile(User user) async {
try {
return await _apiService.updateProfile(user);
} catch (e) {
throw UserException('更新用户信息失败: $e');
}
}
}
iOS | Flutter | 说明 |
---|---|---|
URLSession | Dio | HTTP 客户端 |
Alamofire | Dio | 高级 HTTP 客户端 |
Moya | Retrofit | API 接口抽象 |
Codable | json_annotation | JSON 序列化 |
Flutter 的优势:
iOS 的优势:
class ApiException implements Exception {
final String message;
final int? statusCode;
ApiException(this.message, {this.statusCode});
String toString() => 'ApiException: $message (Status: $statusCode)';
}
// 在拦截器中处理错误
class _ErrorInterceptor extends Interceptor {
void onError(DioException err, ErrorInterceptorHandler handler) {
switch (err.type) {
case DioExceptionType.connectionTimeout:
throw ApiException('连接超时');
case DioExceptionType.receiveTimeout:
throw ApiException('接收超时');
case DioExceptionType.badResponse:
final statusCode = err.response?.statusCode;
final message = err.response?.data['message'] ?? '请求失败';
throw ApiException(message, statusCode: statusCode);
default:
throw ApiException('网络错误: ${err.message}');
}
}
}
// 统一响应格式
class ApiResponse<T> {
final bool success;
final T? data;
final String? message;
final int? code;
ApiResponse({
required this.success,
this.data,
this.message,
this.code,
});
factory ApiResponse.fromJson(Map<String, dynamic> json, T Function(dynamic) fromJson) {
return ApiResponse<T>(
success: json['success'] ?? false,
data: json['data'] != null ? fromJson(json['data']) : null,
message: json['message'],
code: json['code'],
);
}
}
class CacheInterceptor extends Interceptor {
final Map<String, dynamic> _cache = {};
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
if (options.method == 'GET' && _cache.containsKey(options.path)) {
// 返回缓存数据
final cachedResponse = _cache[options.path];
handler.resolve(Response(
data: cachedResponse,
requestOptions: options,
));
return;
}
handler.next(options);
}
void onResponse(Response response, ResponseInterceptorHandler handler) {
if (response.requestOptions.method == 'GET') {
_cache[response.requestOptions.path] = response.data;
}
handler.next(response);
}
}
Dio + Retrofit 的组合为 Flutter 开发者提供了强大而优雅的网络请求解决方案。对于从 iOS 转向 Flutter 的开发者来说,这个组合提供了:
通过合理使用这两个库,你可以构建出健壮、可维护的网络层,为你的 Flutter 应用提供强大的后端支持。
记住,好的网络层设计是应用成功的基础。投入时间学习这些工具,将会在长期开发中带来巨大的回报。