网络层设计与使用
Flu CLI 提供了一个开箱即用、高度封装的网络层(基于 Dio)。它不仅仅是一个 HTTP 客户端,更是一套包含拦截器、异常处理、Mock 数据降级和响应标准化的完整解决方案。
🏗️ 架构设计
网络层位于 lib/core/network,核心组件如下:
- AppHttp (单例): 核心客户端,负责 Dio 实例的创建和配置。
- AppResponse: 统一响应体,所有接口返回的数据都会被标准化为结构化对象。
- Interceptors:
AuthInterceptor: 自动处理 Token 注入。LogInterceptor: 请求和响应日志打印。ErrorInterceptor: 统一错误处理,将 HTTP 错误转化为友好的业务异常。
- ResponseAdapter: 适配器模式,用于处理不同后端接口的 JSON 结构差异。
🚀 快速上手
1. 配置 BaseUrl
在 lib/app.dart 或 MainViewModel 初始化时配置:
dart
// 在应用启动时配置
AppConfig.I.init(
baseUrl: 'https://api.example.com',
connectTimeout: 30000,
);2. 编写 Service
使用 serviceNetwork 代码片段可以快速生成带网络层的 Service:
dart
import '../core/network/app_http.dart';
class ProductService {
final AppHttp _http;
ProductService({AppHttp? http}) : _http = http ?? AppHttp();
/// 获取商品列表
Future<List<Product>> getProductList(int page) async {
// 1. 发起请求
final response = await _http.get(
'/products',
queryParameters: {'page': page},
);
// 2. 处理响应(isSuccess 会自动判断 code == 200)
if (response.isSuccess) {
final list = response.data as List;
return list.map((e) => Product.fromJson(e)).toList();
}
// 3. 错误处理(可选,上层 ViewModel 会捕获异常)
return [];
}
}3. 在 ViewModel 中调用
dart
class ProductListViewModel extends BaseListViewModel<Product> {
final ProductService _service = ProductService();
@override
Future<List<Product>> fetchPage(int page) async {
// Service 内部已经处理了异常,这里只需关注业务数据
return await _service.getProductList(page);
}
}🧩 核心特性详解
1. 统一响应体 (AppResponse)
后端接口千奇百怪,AppResponse 帮你统一成标准格式:
dart
class AppResponse<T> {
final bool isSuccess; // 是否成功 (code == 200)
final int code; // 业务状态码
final String message; // 提示信息
final T? data; // 业务数据 (泛型)
}2. Mock 数据降级
在开发阶段后端接口未就绪时,可以开启 Mock 模式:
dart
// 开启 Mock 模式
AppConfig.I.useMockData = true;在 Service 中支持 Mock 降级:
dart
Future<List<Product>> getProductList() async {
// 如果开启了 Mock,优先返回 Mock 数据
if (AppConfig.I.useMockData) {
return [
Product(id: '1', name: 'Mock商品 A'),
Product(id: '2', name: 'Mock商品 B'),
];
}
// 这行代码在 Mock 模式下不会执行
final response = await _http.get('/products');
// ...
}3. 多环境适配
Flu CLI 模板默认支持多环境配置。你可以创建不同的 Config 类:
dart
// dev_config.dart
const baseUrl = 'https://dev-api.example.com';
// prod_config.dart
const baseUrl = 'https://api.example.com';🔌 适配不同后端
如果你的后端返回结构不是标准的 { code, msg, data },你可以通过自定义 ResponseAdapter 来适配:
dart
// 默认适配器 (DefaultResponseAdapter)
@override
AppResponse<T> adapt(dynamic data) {
return AppResponse(
code: data['code'],
message: data['msg'],
data: data['data'],
);
}你只需要修改 lib/core/network/response_adapter.dart 中的适配逻辑即可。
❓ 常见问题
Q: 如何处理 Token 过期? A: AuthInterceptor 中预留了 401 错误的处理逻辑,你可以在那里添加跳转登录页或刷新 Token 的代码。
Q: 为什么推荐注入 AppHttp? A: ProductService({AppHttp? http}) 这种写法支持依赖注入,方便在编写单元测试时注入 Mock 的 AppHttp 实例。
Q: 是否支持 WebSocket? A: AppHttp 专注于 RESTful API。如需 WebSocket,建议在 lib/core/network 下单独创建一个 SocketClient 类。