Flutter网络API请求插件simple_http_api的使用
Flutter网络API请求插件simple_http_api的使用
本包扩展了官方的 http 包,并简化了 dio 包的核心功能。它是一个开箱即用的包,可以轻松创建 get/post/put/patch/delete 请求并上传文件,避免导入冗余函数。
功能
-
请求重试: 允许通过设置一个
Duration
来重试请求。如果在指定的时间内未收到可接受的响应,则请求将被终止并重新开始。 -
请求取消: 取消请求可以与重试功能一起工作。
-
文件上传: 支持在
Isolate
中上传文件。目前仅支持上传过程中的onUploadProgress
回调。参见 上传示例。 -
接收响应数据作为流: 支持将响应数据作为流接收。参见 接收响应数据作为流示例。
-
开箱即用,参见示例。
使用方法
GET 请求
import 'package:simple_http_api/simple_http_api.dart';
void _get() async {
final url = Uri.parse("http://127.0.0.1:8080");
try {
final res = await Api.get(
url,
headers: {"accept": "application/json"},
cancelToken: TimingToken(Duration(seconds: 2)),
options: ConnectionOption(
connectionTimeout: Duration(seconds: 1),
sendTimeout: Duration(seconds: 1),
receiveTimeout: Duration(seconds: 3),
),
);
print(res);
} catch (e) {
print(e);
}
}
重试GET请求
Future<void> _retryGet([int? delayMs]) async {
final delay = delayMs != null && delayMs > 0 ? "?delay=$delayMs" : "";
final url = Uri.parse("http://127.0.0.1:8080$delay");
try {
final res = await Api.get(
url,
// headers: {"accept": "application/json"},
// cancelToken: TimingToken(Duration(seconds: 3)),
options: ConnectionOption(
connectionTimeout: Duration(seconds: 1),
sendTimeout: Duration(seconds: 1),
// receiveTimeout: Duration(seconds: 2),
),
retryConfig: RetryConfig(
retryTimeout: Duration(seconds: 5),
retries: 3,
// retryWhenException: (e) => e.type != ErrorType.other,
// retryWhenStatus: (code) => code >= 300,
),
);
print(res);
} catch (e) {
print(e);
}
}
POST 请求
import "dart:convert";
import 'package:simple_http_api/simple_http_api.dart';
void _post_() async {
final url = Uri.parse("http://127.0.0.1:8080");
final data = {
"hello": "api",
"delay": "4000",
"list": [100],
};
try {
final res = await Api.post(
url,
headers: {
"accept": "application/json",
"content-type": "application/json",
},
cancelToken: TimingToken(Duration(seconds: 2)),
body: json.encode(data),
options: ConnectionOption(
connectionTimeout: Duration(seconds: 1),
sendTimeout: Duration(seconds: 1),
receiveTimeout: Duration(seconds: 3),
),
);
print(res);
} catch (e) {
print(e);
}
}
重试POST请求
Future<void> _retryPost() async {
final url = Uri.parse("http://127.0.0.1:8080");
final data = {
"hello": "api",
"delay": 2000,
"list": [100],
};
try {
final res = await Api.post(
url,
headers: {
"accept": "application/json",
"content-type": "application/json",
},
body: json.encode(data),
// cancelToken: TimingToken(Duration(seconds: 5)),
options: ConnectionOption(
connectionTimeout: Duration(seconds: 1),
sendTimeout: Duration(seconds: 1),
// receiveTimeout: Duration(seconds: 2),
),
retryConfig: RetryConfig(
retryTimeout: Duration(seconds: 3),
retries: 3,
// retryWhenException: (e) => e.type != ErrorType.other,
retryWhenStatus: (code) => code >= 300,
),
);
print(res);
} catch (e) {
print(e);
}
}
文件上传
import 'dart:async';
import 'package:simple_http_api/simple_http_api.dart';
void main() async {
await _uploadSingle("./assets/demo.mp4");
}
Future<void> _uploadSingle(String path) async {
final url = Uri.parse("http://127.0.0.1:8080/upload/single");
final file = await FormData.fileFromPath(path, field: "single");
final formData = FormData();
formData.addFile(file);
formData.addFields({"upload": "test"});
try {
final res = await Api.upload(url, formData,
cancelToken: TimingToken(Duration(seconds: 3)),
headers: {
"content-type": "application/json",
},
onUploadProgress: (sent, total) =>
print("total: $total, sent: $sent, percent: ${sent / total}"));
print(res);
} catch (e) {
print("e");
}
}
多文件上传
Future<void> _uploadMulti() async {
final url = Uri.parse("http://127.0.0.1:8080/upload/multi");
final file1 =
await FormData.fileFromPath("./assets/demo.mp4", field: "multi");
final file2 =
await FormData.fileFromPath("./assets/demo.png", field: "multi");
final formData = FormData();
formData.addFile(file1);
formData.addFile(file2);
formData.addFields({"upload": "test"});
try {
final res = await Api.upload(
url,
formData,
cancelToken: TimingToken(Duration(seconds: 3)),
headers: {
"content-type": "application/json",
},
);
print(res);
} catch (e) {
print("e");
}
}
接收响应数据作为流
import 'dart:convert';
import 'package:simple_http_api/simple_http_api.dart';
void main() async {
final headers = {
"Content-Type": "application/json",
"Authorization": "Bearer <token>",
};
final url = Uri.parse("https://api.openai.com/v1/completions");
final data = {
"model": "text-davinci-003",
"prompt": "give 5 words",
"max_tokens": 256,
"stream": true,
};
final eventSource = EventSource(url, ApiMethod.post);
eventSource.setHeaders(headers);
final cancelToken = TimingToken(Duration(seconds: 2));
final stream =
eventSource.send(body: json.encode(data), cancelToken: cancelToken);
stream.listen(
(event) {
if (eventSource.isWeb) {
print(event.chunk as String);
} else {
final encoding = event.getEncoding();
print(encoding.decode(event.chunk as List<int>));
}
},
onError: (err) => print(err),
onDone: eventSource.close,
);
}
创建请求
用户必须使用 try-catch
捕获 ApiError
,以防没有返回预期的 ApiResponse
(例如,请求超时或响应不符合预期)。
-
需要指定
headers
中的content-type
字段。如果不指定,会根据body
的类型自动选择不同的媒体类型:- 如果
body
是String
类型 ->text/plain
- 如果
body
是Map<String, String>
类型 ->application/x-www-form-urlencoded
- 如果
body
是List<int>
类型 -> 不应用任何媒体类型 - 如果以上情况都不适用,设置
body
时会抛出ArgumentError
- 如果
-
(可选)指定一种
CancelToken
来确定是否取消此请求。TimingToken
: 这个令牌会在创建HttpRequest
/XMLHttpRequest
之前开始计时。当其令牌过期时,它会调用cancel()
完成请求。因此,HttpRequest
/XMLHttpRequest
将被中止,并抛出ErrorType.cancel
RetryToken
: 如果没有提供RetryConfig
,它将表现得像TimingToken
。如果提供了RetryConfig
,它将与主令牌一起工作以确定是否取消当前请求并开始重试。
-
(可选)指定
ConnectionOption
来控制请求的不同阶段的持续时间。- (Web): 所有三种类型的超时都会尝试完成
Completer
并在其中一个验证成功后强制中止此XMLHttpRequest
。connectionTimeout
在XHR.readyState < 1
后的持续时间内验证成功sendTimeout
在XHR.readyState < 3
和设置了接收开始时间后的持续时间内验证成功receiveTimeout
在onLoadStart
被调用后的持续时间内验证成功
- (移动设备):
HttpClient
会在三个超时中的任何一个验证成功后被强制关闭。connectionTimeout
在创建HttpClient
时设置sendTimeout
在启动addStream
到HttpClientRequest
时激活receiveTimeout
分为两个阶段:1) 尝试获取响应时调用HttpClientRequest.close()
2) 每次接收到数据块时
- (Web): 所有三种类型的超时都会尝试完成
ConnectionOption
如何与 CancelToken
协同工作
通常,CancelToken
可以让用户决定 1) 请求预计完成的总时间 2) 需要在某些意外/故意发生的情况下忽略/取消请求。
ConnectionOption
让用户确定请求的不同阶段预计完成的时间。如果某个阶段的请求花费的时间超过给定的超时时间,它将被直接中止/取消。
ConnectionOption
和 CancelToken
将分别验证自己,并尝试在任何一个验证成功时中止/取消请求。
重试机制如何实现
RetryConfig.retries
限制最大重试次数,而 RetryConfig.retryInterval
限制两次请求之间的间隔。
用户有两种方式停止重试:
- 提供一个
CancelToken
来控制由_RetryClient
创建的RetryToken
(不可直接访问)。一旦CancelToken
过期,重试将停止,并且如果适用,当前请求将被中止。 RetryConfig.retryWhenException
和RetryConfig.retryWhenStatus
一起工作,确定在达到最大重试次数之前是否继续重试。
上述两种方式可以一起工作。
注意:RetryConfig.retryInterval
表示下一次请求将在上一次请求未返回响应时创建并中止前一次请求,而不是等待 retryInterval
后再创建下一次请求。
调查
- 在接收超时时释放资源的最佳方式是什么?
client.close(force: true);
- 或者使用:
response .detachSocket() .then((socket) => socket.destroy()) .catchError( (err) { print("error on detaching socket: $err"); }, test: (error) => true, );
更多关于Flutter网络API请求插件simple_http_api的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter网络API请求插件simple_http_api的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个使用Flutter网络API请求插件simple_http_api
的示例代码。这个插件可以用来简化HTTP请求的发送和处理。
首先,你需要在你的pubspec.yaml
文件中添加这个依赖:
dependencies:
flutter:
sdk: flutter
simple_http_api: ^x.y.z # 请将x.y.z替换为最新的版本号
然后运行flutter pub get
来获取依赖。
接下来,让我们编写一个Flutter应用来演示如何使用simple_http_api
插件。
1. 导入依赖
在你的Dart文件中(例如main.dart
),导入所需的包:
import 'package:flutter/material.dart';
import 'package:simple_http_api/simple_http_api.dart';
2. 配置HTTP客户端
你可以创建一个HTTP客户端实例,并配置一些基础设置,如baseURL和超时时间:
final httpApi = HttpApi(
baseUrl: 'https://api.example.com', // 替换为你的API基础URL
timeout: 10, // 请求超时时间,单位为秒
);
3. 发送GET请求
Future<void> fetchData() async {
try {
final response = await httpApi.get('/endpoint'); // 替换为你的API端点
if (response.isSuccessful) {
final data = await response.data;
print('Data: $data');
} else {
print('Error: ${response.message}');
}
} catch (e) {
print('Exception: $e');
}
}
4. 发送POST请求
Future<void> postData() async {
try {
final body = {
'key1': 'value1',
'key2': 'value2',
};
final response = await httpApi.post('/endpoint', body: body); // 替换为你的API端点
if (response.isSuccessful) {
final data = await response.data;
print('Response Data: $data');
} else {
print('Error: ${response.message}');
}
} catch (e) {
print('Exception: $e');
}
}
5. 在UI中使用
最后,将这些功能集成到你的Flutter UI中。例如,可以创建两个按钮,一个用于发送GET请求,另一个用于发送POST请求:
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Simple HTTP API Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: fetchData,
child: Text('Fetch Data (GET)'),
),
ElevatedButton(
onPressed: postData,
child: Text('Post Data (POST)'),
),
],
),
),
),
);
}
}
完整代码
import 'package:flutter/material.dart';
import 'package:simple_http_api/simple_http_api.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
final httpApi = HttpApi(
baseUrl: 'https://api.example.com', // 替换为你的API基础URL
timeout: 10, // 请求超时时间,单位为秒
);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Simple HTTP API Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: () async {
try {
final response = await httpApi.get('/endpoint'); // 替换为你的API端点
if (response.isSuccessful) {
final data = await response.data;
print('Data: $data');
} else {
print('Error: ${response.message}');
}
} catch (e) {
print('Exception: $e');
}
},
child: Text('Fetch Data (GET)'),
),
ElevatedButton(
onPressed: () async {
try {
final body = {
'key1': 'value1',
'key2': 'value2',
};
final response = await httpApi.post('/endpoint', body: body); // 替换为你的API端点
if (response.isSuccessful) {
final data = await response.data;
print('Response Data: $data');
} else {
print('Error: ${response.message}');
}
} catch (e) {
print('Exception: $e');
}
},
child: Text('Post Data (POST)'),
),
],
),
),
),
);
}
}
请确保替换示例代码中的URL和端点为你实际的API信息。这样,你就可以使用simple_http_api
插件在Flutter应用中发送HTTP请求了。