Flutter网络请求插件http_api的使用
Flutter网络请求插件http_api的使用
概述
http_api
是一个简单而强大的 http
包的封装。它提供了拦截器(中间件)支持、响应缓存支持,并且与 Flutter 集成良好。
特点
- 拦截器 / 中间件:允许在请求前和响应后执行特定任务。
- FormData 支持:方便处理文件上传等表单数据。
- 缓存支持:避免不必要的网络请求,提升用户体验。
- 易于扩展和自定义:可以根据需要轻松扩展功能。
- 跨平台:适用于 Dart 和 Flutter 项目。
重要提示
该库仍在开发中,可能会有破坏性的 API 变更。如果要使用此库,请确保指定要使用的版本,例如:
dependencies:
http_api: 0.7.2+2
入门指南
1. 创建你的 Api 类
通过继承 BaseApi
类来创建你的 Api 类。
// 定义你的 api 类
class Api extends BaseApi {
/// 提供 BaseApi 构造函数所需的数据
Api(Uri url) : super(url);
/// 实现 api 请求方法
Future<PostModel> getPostById(int id) async {
/// 使用 [send] 方法发起 api 请求
final response = await send(ApiRequest(
endpoint: "/posts/$id",
));
/// 处理返回的数据
/// 例如:将 HTTP 响应解析为模型对象
return PostModel.fromJson(response.body);
}
}
2. 使用你的 Api 类
void main() async {
/// 定义 api 基础 URL
final url = Uri.parse("https://example.com/api");
/// 创建 api 实例
final api = Api(url);
/// 发起请求
Post post = await api.getPostById(10);
/// 处理返回的数据
print(post.title);
/// 释放资源
api.dispose();
/// 现在你已经准备好摇滚了!
}
拦截器 / 中间件
拦截器允许你在请求前和响应后执行某些任务。
添加拦截器
通过构造函数的 link
参数提供拦截器。
void main() {
Api(
Uri.parse("https://example.com/api"),
/// 分配拦截器(可以通过链式调用提供多个拦截器)
link: AuthLink()
.chain(LoggerLink(responseBody: true))
.chain(HttpLink()),
);
}
拦截器的工作原理
当你通过 send
(或 cacheAndNetwork
和 cacheIfAvailable
)发起请求时,请求会经过拦截器链,最终到达 HttpLink
,由 HttpLink
发起实际的 HTTP 请求。然后所有拦截器会依次接收到 API 响应,最后返回到 send
方法的调用处。
__________ ____________ __________
calling send() | -request-> | AuthLink | -request-> | LoggerLink | -request-> | HttpLink |
send returns data | <-response- |__________| <-response- |____________| <-response- |__________|
tasks tasks http request
自定义拦截器
你可以通过继承 ApiLink
类来创建自定义拦截器。
/// 创建链接类并继承 [ApiLink]。
class CustomLink extends ApiLink {
/// 覆盖 next 方法。
@override
Future<ApiResponse> next(ApiRequest request) async {
/// 在发送 HTTP 请求之前执行的操作
/// 例如:测量请求耗时
final requestTime = DateTime.now();
/// 调用 super.next 触发下一个拦截器
ApiResponse response = await super.next(request);
/// 在接收到 API 响应后执行的操作
/// 例如:打印请求耗时
final requestDuration = DateTime.now().difference(requestTime);
print(
"Request ${request.id} duration: "
"${requestDuration.inMilliseconds} ms",
);
/// 返回响应
return response;
}
}
如果你的拦截器需要在 API 实例销毁时释放资源,可以覆盖其 dispose
方法。
对于简单的拦截器,创建一个继承 ApiLink
的类可能有些过度设计。因此,你也可以在调用时直接定义拦截器:
ApiLink.next((ApiRequest request, NextFunction next) async {
final requestTime = DateTime.now();
final response = await next(request);
final requestDuration = DateTime.now().difference(requestTime);
print(
"Request ${request.id} duration: "
"${requestDuration.inMilliseconds} ms",
);
return response;
});
缓存
http_api
支持响应缓存,以避免不必要的网络请求或提升用户体验。
添加缓存
- 在你的 Api 类中添加
Cache
混合。
- class Api extends BaseApi {
+ class Api extends BaseApi with Cache {
- 提供一个缓存管理器。
class Api extends BaseApi with Cache {
/// 提供一个缓存管理器
/// 该库提供了一个内存缓存管理器实现
@override
CacheManager createCacheManager() => InMemoryCache();
/// ** 你的自定义 Api 类实现 **
}
- 完成!
现在你可以利用响应缓存了。
缓存混合
缓存混合为你的 API 实例添加了 cacheAndNetwork
和 cacheIfAvailable
方法,以及可通过 cache
属性访问的缓存管理器。
默认情况下,每个包含 key
参数且响应成功的请求会自动更新缓存。你可以通过覆盖 shouldUpdateCache
方法来决定哪些响应应该保存到缓存中。
cacheIfAvailable
从缓存中检索响应,如果没有则回退到网络请求。返回类型为 Future<ApiResponse>
。
cacheAndNetwork
先从缓存中检索响应,如果可用则返回缓存响应,否则发起网络请求。返回类型为 Stream<ApiResponse>
。
示例:
// Api.dart
class Api extends BaseApi with Cache {
@override
CacheManager createCacheManager() => InMemoryCache();
Stream<PostModel> getPostById(int id) {
Stream<ApiResponse> request = ApiRequest(
/// 缓存键是必需的
/// 响应将根据此键缓存和检索
key: CacheKey("posts/$id"),
endpoint: "/posts/${id}",
);
/// 因为 `cacheAndNetwork` 方法返回 Stream,我们可以利用其所有特性
/// 例如:将响应转换为模型对象
final transformResponseToPostModel =
StreamTransformer<ApiResponse, PostModel>.fromHandlers(
handleData: (response, sink) => sink.add(
PostModel.fromJson(response.body),
),
);
/// 返回转换后的流
return cacheAndNetwork(request)
.transform(transformResponseToPostModel);
}
/// ** 你的自定义 Api 类实现 **
}
cache
cache
属性包含一个通过 createCacheManager
方法内部创建的 CacheManager
实例。通过此属性,你可以手动操作缓存。
示例:
/// 将新响应保存到缓存并检索之前保存的响应
ApiResponse saveResponseToCache(CacheKey key, ApiResponse response) async {
final oldResponse = await api.cache.read(key);
await api.cache.write(key, response);
return oldResponse;
}
shouldUpdateCache
决定是否将与请求相关的响应保存到缓存中。
默认实现:
bool shouldUpdateCache(ApiRequest request, ApiResponse response) {
return request.key != null && response.ok;
}
FormData
处理表单数据,包括文件上传。
示例:
/// 创建 [FormData] 实例
final formData = FormData();
/// 添加字段
formData.append('photo[visible]', true);
formData.append('photo[type]', 'image/png');
formData.append('photo[size]', 1920);
/// 添加文件
File file = getImageFile();
formData.appendFile('photo[file]', file, filename: "my_filename.png");
/// 通过 api 类发送文件
final response = await api.post("/photos/upload", body: formData);
http_api 和 Flutter ♥️
http_api
包与 Dart 和 Flutter 项目都兼容良好。
提示
你可以使用 provider
包将你的 Api 实例提供给 widget 树中的其他组件。
示例:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Provider(
create: (_) => Api(
/// 提供基础 URL
url: Uri.parse("https://example.com/api"),
/// 分配中间件(可以通过链式调用提供多个中间件)
link: LoggerLink(responseDuration: true, endpoint: true)
.chain(HttpLink()),
),
child: MaterialApp(
title: 'http_api example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
initialRoute: "home",
routes: {
"basic": (_) => BasicExample(),
"cache": (_) => CacheExample(),
"home": (_) => HomeScreen(),
},
),
);
}
}
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('http_api examples'),
),
body: SafeArea(
child: SizedBox(
width: double.infinity,
child: ListView(
padding: EdgeInsets.all(15),
children: <Widget>[
ElevatedButton(
onPressed: () => Navigator.of(context).pushNamed("basic"),
child: Text("Basic example"),
),
ElevatedButton(
onPressed: () => Navigator.of(context).pushNamed("cache"),
child: Text("Cache example"),
),
],
),
),
),
);
}
}
TODO
- 改进文档
- 改进 README 文件
- 添加开发工具
希望这些信息对你有所帮助!如果你有任何问题或需要进一步的帮助,请随时提问。
更多关于Flutter网络请求插件http_api的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html