Flutter网络请求高级技巧

1. 核心概念

1.1 网络库

  • http:Flutter官方推荐的网络库
  • dio:功能强大的第三方网络库
  • retrofit:基于Dart注解的REST客户端生成器

1.2 请求方法

  • GET:获取资源
  • POST:创建资源
  • PUT:更新资源
  • DELETE:删除资源
  • PATCH:部分更新资源

1.3 响应处理

  • 状态码:HTTP状态码
  • 响应体:服务器返回的数据
  • 错误处理:网络错误、服务器错误

2. 高级技巧

2.1 基础网络请求

// 使用http库
import 'package:http/http.dart' as http;

Future<void> fetchData() async {
  try {
    final response = await http.get(Uri.parse('https://api.example.com/data'));
    if (response.statusCode == 200) {
      // 处理成功响应
      print('Response: ${response.body}');
    } else {
      // 处理错误响应
      print('Error: ${response.statusCode}');
    }
  } catch (e) {
    // 处理网络错误
    print('Network error: $e');
  }
}

// 使用dio库
import 'package:dio/dio.dart';

Future<void> fetchDataWithDio() async {
  try {
    final dio = Dio();
    final response = await dio.get('https://api.example.com/data');
    // 处理成功响应
    print('Response: ${response.data}');
  } catch (e) {
    // 处理错误
    print('Error: $e');
  }
}

2.2 拦截器

// 创建dio实例
final dio = Dio();

// 添加请求拦截器
dio.interceptors.add(InterceptorsWrapper(
  onRequest: (options, handler) {
    // 在发送请求之前做一些处理
    print('Request: ${options.uri}');
    // 添加认证token
    options.headers['Authorization'] = 'Bearer your-token';
    return handler.next(options);
  },
  onResponse: (response, handler) {
    // 在收到响应后做一些处理
    print('Response: ${response.statusCode}');
    return handler.next(response);
  },
  onError: (DioException e, handler) {
    // 处理错误
    print('Error: ${e.message}');
    return handler.next(e);
  },
));

// 使用带拦截器的dio实例
Future<void> fetchData() async {
  try {
    final response = await dio.get('https://api.example.com/data');
    print('Response: ${response.data}');
  } catch (e) {
    print('Error: $e');
  }
}

2.3 错误处理

Future<void> fetchData() async {
  try {
    final dio = Dio();
    final response = await dio.get('https://api.example.com/data');
    print('Response: ${response.data}');
  } on DioException catch (e) {
    if (e.response != null) {
      // 服务器返回错误状态码
      print('Server error: ${e.response?.statusCode}');
      print('Error data: ${e.response?.data}');
    } else {
      // 网络错误
      print('Network error: ${e.message}');
    }
  } catch (e) {
    // 其他错误
    print('Error: $e');
  }
}

// 自定义错误处理类
class ApiError {
  final int statusCode;
  final String message;

  ApiError(this.statusCode, this.message);

  factory ApiError.fromDioException(DioException e) {
    if (e.response != null) {
      return ApiError(
        e.response!.statusCode!, 
        e.response!.data['message'] ?? 'Server error',
      );
    } else {
      return ApiError(0, e.message ?? 'Network error');
    }
  }
}

Future<void> fetchDataWithCustomError() async {
  try {
    final dio = Dio();
    final response = await dio.get('https://api.example.com/data');
    print('Response: ${response.data}');
  } on DioException catch (e) {
    final error = ApiError.fromDioException(e);
    print('Error: ${error.statusCode} - ${error.message}');
  }
}

2.4 缓存

// 使用dio的缓存拦截器
import 'package:dio_cache_interceptor/dio_cache_interceptor.dart';
import 'package:dio_cache_interceptor_hive_store/dio_cache_interceptor_hive_store.dart';

void setupDio() {
  // 缓存配置
  final cacheOptions = CacheOptions(
    store: HiveCacheStore('.cache'),
    policy: CachePolicy.request, // 请求时缓存
    maxStale: Duration(days: 7), // 缓存最大过期时间
    priority: CachePriority.normal,
  );

  // 创建dio实例
  final dio = Dio()..interceptors.add(DioCacheInterceptor(options: cacheOptions));
}

// 手动缓存
class ApiService {
  final Dio _dio;
  final Map<String, Response> _cache = {};

  ApiService(this._dio);

  Future<Response> get(String url) async {
    // 检查缓存
    if (_cache.containsKey(url)) {
      return _cache[url]!;
    }

    // 发起请求
    final response = await _dio.get(url);
    
    // 缓存响应
    _cache[url] = response;
    
    return response;
  }

  void clearCache() {
    _cache.clear();
  }
}

2.5 文件上传和下载

// 文件上传
Future<void> uploadFile() async {
  final dio = Dio();
  
  // 单文件上传
  final formData = FormData.fromMap({
    'name': 'John Doe',
    'file': await MultipartFile.fromFile('path/to/file.jpg', filename: 'photo.jpg'),
  });

  try {
    final response = await dio.post('https://api.example.com/upload', data: formData);
    print('Upload successful: ${response.data}');
  } catch (e) {
    print('Upload error: $e');
  }
}

// 多文件上传
Future<void> uploadMultipleFiles() async {
  final dio = Dio();
  
  final formData = FormData.fromMap({
    'name': 'John Doe',
    'files': [
      await MultipartFile.fromFile('path/to/file1.jpg', filename: 'photo1.jpg'),
      await MultipartFile.fromFile('path/to/file2.jpg', filename: 'photo2.jpg'),
    ],
  });

  try {
    final response = await dio.post('https://api.example.com/upload-multiple', data: formData);
    print('Upload successful: ${response.data}');
  } catch (e) {
    print('Upload error: $e');
  }
}

// 文件下载
Future<void> downloadFile() async {
  final dio = Dio();
  
  try {
    final response = await dio.download(
      'https://api.example.com/file',
      'path/to/save/file.pdf',
      onReceiveProgress: (count, total) {
        print('Download progress: ${(count / total * 100).toStringAsFixed(0)}%');
      },
    );
    print('Download successful');
  } catch (e) {
    print('Download error: $e');
  }
}

2.6 网络状态管理

// 检查网络状态
import 'package:connectivity_plus/connectivity_plus.dart';

Future<void> checkNetworkStatus() async {
  final connectivityResult = await (Connectivity().checkConnectivity());
  if (connectivityResult == ConnectivityResult.none) {
    print('No internet connection');
  } else if (connectivityResult == ConnectivityResult.mobile) {
    print('Connected to mobile network');
  } else if (connectivityResult == ConnectivityResult.wifi) {
    print('Connected to wifi');
  }
}

// 监听网络状态变化
void listenToNetworkChanges() {
  Connectivity().onConnectivityChanged.listen((ConnectivityResult result) {
    if (result == ConnectivityResult.none) {
      print('No internet connection');
    } else if (result == ConnectivityResult.mobile) {
      print('Connected to mobile network');
    } else if (result == ConnectivityResult.wifi) {
      print('Connected to wifi');
    }
  });
}

// 网络状态管理服务
class NetworkService {
  final Connectivity _connectivity = Connectivity();
  Stream<ConnectivityResult> get onNetworkChange => _connectivity.onConnectivityChanged;

  Future<bool> isConnected() async {
    final result = await _connectivity.checkConnectivity();
    return result != ConnectivityResult.none;
  }
}

3. 最佳实践

3.1 代码组织

  • 服务层:将网络请求封装为服务
  • 模型层:定义数据模型
  • 存储层:处理缓存和本地存储
  • 工具类:提取通用的网络工具函数

3.2 性能优化

  • 缓存:合理使用缓存减少网络请求
  • 批量请求:合并多个请求减少网络开销
  • 压缩:使用gzip压缩减少数据传输量
  • 超时设置:合理设置请求超时时间
  • 重试机制:实现请求重试逻辑

3.3 安全性

  • HTTPS:使用HTTPS协议
  • 认证:使用安全的认证方式
  • 加密:加密敏感数据
  • 防注入:防止SQL注入等攻击
  • CORS:正确配置CORS

3.4 可测试性

  • 模拟网络请求:使用mock数据进行测试
  • 单元测试:测试网络服务的各个部分
  • 集成测试:测试网络请求的完整流程

4. 实际应用

4.1 电商应用网络服务

// 产品服务
class ProductService {
  final Dio _dio;

  ProductService(this._dio);

  Future<List<Product>> getProducts() async {
    try {
      final response = await _dio.get('/products');
      final List<dynamic> data = response.data;
      return data.map((item) => Product.fromJson(item)).toList();
    } catch (e) {
      print('Error fetching products: $e');
      throw e;
    }
  }

  Future<Product> getProductById(String id) async {
    try {
      final response = await _dio.get('/products/$id');
      return Product.fromJson(response.data);
    } catch (e) {
      print('Error fetching product: $e');
      throw e;
    }
  }

  Future<Product> createProduct(Product product) async {
    try {
      final response = await _dio.post('/products', data: product.toJson());
      return Product.fromJson(response.data);
    } catch (e) {
      print('Error creating product: $e');
      throw e;
    }
  }

  Future<Product> updateProduct(String id, Product product) async {
    try {
      final response = await _dio.put('/products/$id', data: product.toJson());
      return Product.fromJson(response.data);
    } catch (e) {
      print('Error updating product: $e');
      throw e;
    }
  }

  Future<void> deleteProduct(String id) async {
    try {
      await _dio.delete('/products/$id');
    } catch (e) {
      print('Error deleting product: $e');
      throw e;
    }
  }
}

// 购物车服务
class CartService {
  final Dio _dio;

  CartService(this._dio);

  Future<List<CartItem>> getCart() async {
    try {
      final response = await _dio.get('/cart');
      final List<dynamic> data = response.data;
      return data.map((item) => CartItem.fromJson(item)).toList();
    } catch (e) {
      print('Error fetching cart: $e');
      throw e;
    }
  }

  Future<CartItem> addToCart(String productId, int quantity) async {
    try {
      final response = await _dio.post('/cart', data: {
        'product_id': productId,
        'quantity': quantity,
      });
      return CartItem.fromJson(response.data);
    } catch (e) {
      print('Error adding to cart: $e');
      throw e;
    }
  }

  Future<void> removeFromCart(String itemId) async {
    try {
      await _dio.delete('/cart/$itemId');
    } catch (e) {
      print('Error removing from cart: $e');
      throw e;
    }
  }

  Future<CartItem> updateQuantity(String itemId, int quantity) async {
    try {
      final response = await _dio.put('/cart/$itemId', data: {
        'quantity': quantity,
      });
      return CartItem.fromJson(response.data);
    } catch (e) {
      print('Error updating quantity: $e');
      throw e;
    }
  }
}

4.2 社交应用网络服务

// 用户服务
class UserService {
  final Dio _dio;

  UserService(this._dio);

  Future<User> login(String email, String password) async {
    try {
      final response = await _dio.post('/auth/login', data: {
        'email': email,
        'password': password,
      });
      // 存储token
      final token = response.data['token'];
      _dio.options.headers['Authorization'] = 'Bearer $token';
      return User.fromJson(response.data['user']);
    } catch (e) {
      print('Error logging in: $e');
      throw e;
    }
  }

  Future<User> register(User user) async {
    try {
      final response = await _dio.post('/auth/register', data: user.toJson());
      return User.fromJson(response.data['user']);
    } catch (e) {
      print('Error registering: $e');
      throw e;
    }
  }

  Future<User> getProfile() async {
    try {
      final response = await _dio.get('/users/profile');
      return User.fromJson(response.data);
    } catch (e) {
      print('Error fetching profile: $e');
      throw e;
    }
  }

  Future<User> updateProfile(User user) async {
    try {
      final response = await _dio.put('/users/profile', data: user.toJson());
      return User.fromJson(response.data);
    } catch (e) {
      print('Error updating profile: $e');
      throw e;
    }
  }
}

// 帖子服务
class PostService {
  final Dio _dio;

  PostService(this._dio);

  Future<List<Post>> getPosts() async {
    try {
      final response = await _dio.get('/posts');
      final List<dynamic> data = response.data;
      return data.map((item) => Post.fromJson(item)).toList();
    } catch (e) {
      print('Error fetching posts: $e');
      throw e;
    }
  }

  Future<Post> createPost(Post post) async {
    try {
      final response = await _dio.post('/posts', data: post.toJson());
      return Post.fromJson(response.data);
    } catch (e) {
      print('Error creating post: $e');
      throw e;
    }
  }

  Future<Post> updatePost(String id, Post post) async {
    try {
      final response = await _dio.put('/posts/$id', data: post.toJson());
      return Post.fromJson(response.data);
    } catch (e) {
      print('Error updating post: $e');
      throw e;
    }
  }

  Future<void> deletePost(String id) async {
    try {
      await _dio.delete('/posts/$id');
    } catch (e) {
      print('Error deleting post: $e');
      throw e;
    }
  }

  Future<void> likePost(String id) async {
    try {
      await _dio.post('/posts/$id/like');
    } catch (e) {
      print('Error liking post: $e');
      throw e;
    }
  }

  Future<void> unlikePost(String id) async {
    try {
      await _dio.delete('/posts/$id/like');
    } catch (e) {
      print('Error unliking post: $e');
      throw e;
    }
  }
}

// 评论服务
class CommentService {
  final Dio _dio;

  CommentService(this._dio);

  Future<List<Comment>> getComments(String postId) async {
    try {
      final response = await _dio.get('/posts/$postId/comments');
      final List<dynamic> data = response.data;
      return data.map((item) => Comment.fromJson(item)).toList();
    } catch (e) {
      print('Error fetching comments: $e');
      throw e;
    }
  }

  Future<Comment> createComment(String postId, String content) async {
    try {
      final response = await _dio.post('/posts/$postId/comments', data: {
        'content': content,
      });
      return Comment.fromJson(response.data);
    } catch (e) {
      print('Error creating comment: $e');
      throw e;
    }
  }

  Future<void> deleteComment(String commentId) async {
    try {
      await _dio.delete('/comments/$commentId');
    } catch (e) {
      print('Error deleting comment: $e');
      throw e;
    }
  }
}

5. 总结

Flutter网络请求的高级技巧包括:

  • 使用不同的网络库(http、dio、retrofit)
  • 实现拦截器和错误处理
  • 使用缓存和文件上传下载
  • 管理网络状态
  • 组织清晰的网络服务架构

通过掌握这些技巧,你可以创建出更加可靠、高效的Flutter应用,提升用户体验和应用的性能。

更多推荐