Flutter网络请求插件http_client_plugin的使用
Flutter网络请求插件http_client_plugin的使用
Http Client Plugin
Http Client Plugin 是一个由 Tachyon
驱动的代码生成器。
该插件允许你使用 Dio
作为 HTTP 客户端来生成 HTTP 服务。
如何工作
Http Client Plugin 使用 Tachyon
作为其构建引擎以提供快速的代码生成。此外,该插件使用 analyzer
系统和 analyzer plugin
来访问源代码,解析它并基于此提供 code actions
。
这些 code actions
类似于语言提供的功能(例如 wrap with try/catch
),因此你无需依赖代码片段或手动输入任何样板代码。
安装
- 在你的项目的
pubspec.yaml
文件中添加:
dependencies:
http_client_plugin: any
dev_dependencies:
tachyon: any
- 在项目的根目录下创建
tachyon_config.yaml
文件:
file_generation_paths: # 哪些文件/路径包含在构建中
- "file/path/to/watch"
- "another/one"
generated_file_line_length: 80 # 默认行长度
plugins:
- http_client_plugin # 注册 http_client_plugin
- 更新你的
analysis_options.yaml
文件(以启用code actions
):
最小化 analysis_options.yaml
include: package:lints/recommended.yaml
# 你需要在 analyzer > plugins 下注册插件
analyzer:
plugins:
- http_client_plugin
- 重启分析服务器
VSCode
- 打开命令面板
- Windows/Linux: Ctrl + Shift + P
- MacOS: ⌘ + Shift + P
- 输入并选择 “Dart: Restart Analysis Server”
IntelliJ
- 打开查找操作
- Windows/Linux: Ctrl + Shift + A
- MacOS: ⌘ + Shift + A
- 输入并选择 “Restart Dart Analysis Server”
生成你想要的代码
HttpService 注解
- 创建一个简单的类,并用
[@HttpService](/user/HttpService)()
进行注解:
[@HttpService](/user/HttpService)()
class AppHttpService { ... }
- 添加一个抽象方法,该方法用
[@HttpMethod](/user/HttpMethod).*
注解,并且返回类型为FutureHttpResult<*>
:
[@HttpService](/user/HttpService)()
class AppHttpService {
[@HttpMethod](/user/HttpMethod).get('/user')
FutureHttpResult<User> getUser([@QueryParam](/user/QueryParam)() int userId);
}
- 在 IDE 中运行代码动作
VSCode
- Windows/Linux: Ctrl + .
- MacOS: ⌘ + .
IntelliJ
- Windows/Linux: Alt + Enter
- MacOS: ⌘ + Enter
- 选择
Generate http services
这将生成所有源文件中的样板代码。
现在为了生成部分文件代码,你需要运行 tachyon
。
执行 tachyon
:
dart run tachyon build
更多关于 tachyon
的选项可以通过执行 dart run tachyon --help
查看。
注解
HttpService
注解一个类为 HTTP 服务类。
接收一个可选的 path
参数。
示例:
[@HttpService](/user/HttpService)('/api/v0') // 所有路径将以 /api/v0 开头
class AppHttpService {
[@HttpMethod](/user/HttpMethod).get('/ping') // 这将变成基础 URL + /api/v0 + /ping
FutureHttpResult<void> ping();
}
HttpMethod
注解一个方法以指定使用的 HTTP 动词。可用的 HttpMethod
动词包括:
HttpMethod.get()
HttpMethod.post()
HttpMethod.put()
HttpMethod.delete()
接收一个必需的 path
参数。路径可以为空字符串。
示例:
[@HttpService](/user/HttpService)()
class AppHttpService {
[@HttpMethod](/user/HttpMethod).get('/users')
FutureHttpResult<List<User>> getUsers();
}
QueryParam
注解一个方法的参数为查询参数。
接收一个可选的替代名称作为查询参数。
示例:
[@HttpService](/user/HttpService)()
class AppHttpService {
[@HttpMethod](/user/HttpMethod).get('/user')
FutureHttpResult<User> getUser(
// 查询参数将设置为 "userId"。参见下一个示例如何更改
[@QueryParam](/user/QueryParam)() int userId
);
}
提供不同的查询参数名称:
[@HttpService](/user/HttpService)()
class AppHttpService {
[@HttpMethod](/user/HttpMethod).get('/user')
FutureHttpResult<User> getUser([@QueryParam](/user/QueryParam)('user_id') int userId);
}
PathParam
注解一个方法的参数为路径参数。
与 HttpMethod
注解一起使用时,如果路径段以 :
开始,且匹配段名的注解参数([@PathParam](/user/PathParam)
),则参数值将替换该段。
示例:
[@HttpService](/user/HttpService)()
class AppHttpService {
[@HttpMethod](/user/HttpMethod).get('/user/:id') // 这将变成 /user/<id 的值>
FutureHttpResult<User> getUser([@PathParam](/user/PathParam)() int id);
}
HttpPayload
注解一个方法的参数为请求的有效载荷。
这可以是任何基本类型(或包含基本数据的列表或映射)。还内置支持 Uri
(使用 toString
)和 DateTime
(使用 toIso8601String
)。
还可以使用包含 toJson
方法返回上述内容的类对象。
示例:
[@HttpService](/user/HttpService)()
class AppHttpService {
[@HttpMethod](/user/HttpMethod).post('/user/:id')
FutureHttpResult<User> updateUser(@HttpPayload() Map<String, dynamic> data);
}
HttpHeader
注解一个方法以添加额外的 HTTP 头。
示例:
[@HttpService](/user/HttpService)()
class AppHttpService {
[@HttpMethod](/user/HttpMethod).post('/user/:id')
@HttpHeader('Content-Type', 'application/json')
@HttpHeader('Accept', 'application/json')
FutureHttpResult<User> updateUser(@HttpPayload() Map<String, dynamic> data);
}
HttpMultipart
注解一个方法为多部分请求。
可选地接受一个参数 listFormat
,指示列表应如何格式化,默认值为 MultipartListFormat.multi
。更多选项可以在 这里 查看。
示例:
[@HttpService](/user/HttpService)()
class AppHttpService {
[@HttpMethod](/user/HttpMethod).post('/user')
[@HttpMultipart](/user/HttpMultipart)()
FutureHttpResult<User> updateUser({
@HttpFormField() required String username,
@HttpFormField() required String password,
});
}
HttpFormField
注解一个方法的参数为多部分请求的表单字段。
示例:
[@HttpService](/user/HttpService)()
class AppHttpService {
[@HttpMethod](/user/HttpMethod).post('/user')
[@HttpMultipart](/user/HttpMultipart)()
FutureHttpResult<User> updateUser({
@HttpFormField() required String username,
@HttpFormField(name: 'pass') required String password,
});
}
多部分请求也可以接受文件,使用 HttpFormField.file
注解。该注解的参数类型应该是 String
,并且包含指向文件路径的值。
示例:
[@HttpService](/user/HttpService)()
class AppHttpService {
[@HttpMethod](/user/HttpMethod).post('/user')
[@HttpMultipart](/user/HttpMultipart)()
FutureHttpResult<User> updateUser({
@HttpFormField() required String username,
@HttpFormField(name: 'pass') required String password,
@HttpFormField.file() required String pathToFile,
});
}
HTTP 服务
HTTP 服务可以嵌套,以提供更方便易读的代码。
[@HttpService](/user/HttpService)()
class AppHttpService {
UsersHttpService get users;
}
[@HttpService](/user/HttpService)()
class UsersHttpService {
[@HttpMethod](/user/HttpMethod).get('/user/:id')
FutureHttpResult<User> getById([@PathParam](/user/PathParam)() int id);
}
...
final AppHttpService httpService = AppHttpService();
final HttpResult<User> result = await httpService.users.getById(11);
HTTP 服务也可以通过添加一个抽象方法 overrideHttpClient
来覆盖默认的 Dio
客户端。
[@HttpService](/user/HttpService)()
class UsersHttpService {
UsersHttpService overrideHttpClient(Dio client);
}
HTTP 方法
HTTP 方法必须具有 FutureHttpResult<*>
的返回类型。
FutureHttpResult
是 Future<HttpResult<*>>
的快捷方式。
HttpResult
是一个密封类,由以下两种变体实现:
-
HttpResultData
包含来自成功响应的解析数据。
-
HttpResultFailure
包含从该请求抛出的异常和可选的堆栈跟踪。
HttpResult
提供辅助方法(when
和 maybeWhen
),这些方法接受基于结果的回调。
你还可以使用 asRecord
方法将结果转换为记录,格式为 (T?, Exception?, StackTrace?)
。
示例
查看 这里 的示例。
示例代码
import 'package:dio/dio.dart';
import 'package:example/jsonplaceholderapi.dart';
import 'package:example/models/order.dart';
import 'package:example/models/payment_method.dart';
import 'package:example/models/user.dart';
import 'package:http_client_plugin/http_client_plugin.dart';
part 'example.gen.dart';
[@HttpService](/user/HttpService)()
abstract class AppHttpService {
AppHttpService._();
factory AppHttpService(
Dio client, [
String pathPrefix,
]) = _$AppHttpServiceImpl;
AppHttpService overrideHttpClient(Dio client);
UsersService get user;
PaymentMethodsService get paymentMethods;
GooglePlacesService get places;
JsonPlaceholderHttpService get jsonPlaceholder;
}
[@HttpService](/user/HttpService)('/users')
abstract class UsersService {
UsersService._();
factory UsersService(
Dio client, [
String pathPrefix,
]) = _$UsersServiceImpl;
UsersService overrideHttpClient(Dio client);
OrdersService get orders;
[@HttpMethod](/user/HttpMethod).post('')
FutureHttpResult<User> get([@QueryParam](/user/QueryParam)() int id);
[@HttpMethod](/user/HttpMethod).post('/update')
FutureHttpResult<User> updateUser({
@HttpPayload() User data = const User(id: '11', username: '11'),
});
[@HttpMethod](/user/HttpMethod).post('/register')
[@HttpMultipart](/user/HttpMultipart)()
FutureHttpResult<User> register({
@HttpFormField() required String username,
@HttpFormField() required String password,
@HttpFormField(name: 'user.name') required String name,
@HttpFormField() required int age,
@HttpFormField.file(name: 'picture') required String filePath,
});
}
[@HttpService](/user/HttpService)('/:userId/orders')
abstract class OrdersService {
OrdersService._();
factory OrdersService(
Dio client, [
String pathPrefix,
]) = _$OrdersServiceImpl;
OrdersService overrideHttpClient(Dio client);
[@HttpMethod](/user/HttpMethod).get('')
FutureHttpResult<Order> getOrderById({
[@PathParam](/user/PathParam)() required int userId,
[@QueryParam](/user/QueryParam)() required int id,
});
[@HttpMethod](/user/HttpMethod).get('/all')
FutureHttpResult<List<Order>> getOrders([@PathParam](/user/PathParam)() int userId);
}
[@HttpService](/user/HttpService)('/payment-methods')
abstract class PaymentMethodsService {
PaymentMethodsService._();
factory PaymentMethodsService(
Dio client, [
String pathPrefix,
]) = _$PaymentMethodsServiceImpl;
PaymentMethodsService overrideHttpClient(Dio client);
[@HttpMethod](/user/HttpMethod).get('/:userId/list')
FutureHttpResult<List<PaymentMethod>> getAll([@PathParam](/user/PathParam)() int userId);
}
enum GoogleApiResponseOutput {
json,
xml;
[@override](/user/override)
String toString() => name;
}
[@HttpService](/user/HttpService)('maps/api/place')
abstract class GooglePlacesService {
GooglePlacesService._();
factory GooglePlacesService(
Dio client, [
String pathPrefix,
]) = _$GooglePlacesServiceImpl;
GooglePlacesService overrideHttpClient(Dio client);
[@HttpMethod](/user/HttpMethod).get('/autocomplete')
FutureHttpResult<Map<String, dynamic>> autocomplete({
[@QueryParam](/user/QueryParam)() required String query,
[@QueryParam](/user/QueryParam)() int limit = 25,
[@QueryParam](/user/QueryParam)('apiKey') required int key,
[@QueryParam](/user/QueryParam)('output') GoogleApiResponseOutput output = GoogleApiResponseOutput.json,
});
}
void main() async {
final Dio httpClient = Dio(BaseOptions(
baseUrl: 'http://localhost:3000/api',
connectTimeout: const Duration(seconds: 30),
sendTimeout: const Duration(seconds: 30),
receiveTimeout: const Duration(seconds: 30),
))
..interceptors.add(LogInterceptor());
final AppHttpService httpService = AppHttpService(httpClient);
// httpService.places 将使用不同的 HTTP 客户端
httpService.places.overrideHttpClient(Dio(
BaseOptions(baseUrl: 'https://maps.googleapis.com'),
));
httpService.jsonPlaceholder.overrideHttpClient(Dio(
BaseOptions(baseUrl: 'https://jsonplaceholder.typicode.com'),
));
final HttpResult<User> getUserResult = await httpService.user.get(11);
switch (getUserResult) {
case HttpResultData<User>(:final User data):
print(data);
case HttpResultFailure<User>(:final Exception exception) when exception is DioException:
print(exception);
default:
print('Something went bad');
}
final HttpResult<Post> getPost = await httpService.jsonPlaceholder.posts.getById(1);
switch (getPost.asRecord()) {
case (Post? post, _, _) when post != null:
print('\nGot post');
print(post);
case (_, Exception? exception, _) when exception != null:
print(exception);
}
}
更多关于Flutter网络请求插件http_client_plugin的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter网络请求插件http_client_plugin的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
http_client_plugin
是一个用于 Flutter 的网络请求插件,它提供了一种简单的方式来执行 HTTP 请求。虽然它可能不是 Flutter 社区中最流行的网络请求插件(如 http
或 dio
),但它仍然是一个有用的工具,尤其是在你需要在项目中使用特定的网络请求功能时。
以下是如何在 Flutter 项目中使用 http_client_plugin
的基本步骤:
1. 添加依赖
首先,你需要在 pubspec.yaml
文件中添加 http_client_plugin
的依赖:
dependencies:
flutter:
sdk: flutter
http_client_plugin: ^latest_version
然后运行 flutter pub get
来获取依赖。
2. 导入插件
在你的 Dart 文件中导入 http_client_plugin
:
import 'package:http_client_plugin/http_client_plugin.dart';
3. 创建 HTTP 客户端实例
你可以通过 HttpClientPlugin
类创建一个 HTTP 客户端实例:
final httpClient = HttpClientPlugin();
4. 执行 HTTP 请求
使用 httpClient
实例来执行 HTTP 请求。例如,执行一个 GET 请求:
void fetchData() async {
try {
final response = await httpClient.get('https://jsonplaceholder.typicode.com/posts');
if (response.statusCode == 200) {
print('Data fetched successfully: ${response.body}');
} else {
print('Failed to load data: ${response.statusCode}');
}
} catch (e) {
print('Error: $e');
}
}
5. 处理响应
你可以通过 response.body
访问响应体,并通过 response.statusCode
获取状态码。
6. 其他 HTTP 方法
http_client_plugin
还支持其他 HTTP 方法,如 POST、PUT、DELETE 等。例如,执行一个 POST 请求:
void postData() async {
try {
final response = await httpClient.post(
'https://jsonplaceholder.typicode.com/posts',
body: {
'title': 'foo',
'body': 'bar',
'userId': 1,
},
);
if (response.statusCode == 201) {
print('Data posted successfully: ${response.body}');
} else {
print('Failed to post data: ${response.statusCode}');
}
} catch (e) {
print('Error: $e');
}
}
7. 处理错误
在请求过程中,可能会遇到网络错误或其他异常。你可以使用 try-catch
块来捕获并处理这些错误。
8. 配置请求
你可以在请求中添加 headers、query 参数等。例如:
void fetchDataWithHeaders() async {
try {
final response = await httpClient.get(
'https://jsonplaceholder.typicode.com/posts',
headers: {
'Authorization': 'Bearer your_token',
},
);
if (response.statusCode == 200) {
print('Data fetched successfully: ${response.body}');
} else {
print('Failed to load data: ${response.statusCode}');
}
} catch (e) {
print('Error: $e');
}
}
9. 关闭客户端
在不再需要使用 HTTP 客户端时,可以关闭它以释放资源:
httpClient.close();