1. 介绍
Nylo 使应用程序中的网络请求变得简单。您可以通过基网络类执行 GET、PUT、POST 和 DELETE 请求。内部网络库使用Dio,一个强大的HTTP客户端。
默认的 API 服务目录位于此处 app/networking/*
Nylo 的模版将包括默认的 API 服务 app/networking/api_service.dart
。
dart
class ApiService extends BaseApiService {
ApiService({BuildContext? buildContext}) : super(buildContext);
@override
String get baseUrl => "https://jsonplaceholder.typicode.com";
@override
final interceptors = {
LoggingInterceptor: LoggingInterceptor()
};
Future<User?> fetchUsers() async {
return await network<User>(
request: (request) => request.get("/users"),
);
}
使用 BaseApiService 类可覆盖的变量。
baseUrl
- 这是 API 的基本 URL,例如"jsonplaceholder.typicode.com"。interceptors
- 在这里,您可以添加 Dio 拦截器。在此处了解有关拦截器的更多信息。useInterceptors
- 您可以将其设置为 true 或 false。它将让 API 服务知道是否使用您的拦截器。
2. HTTP 请求
在 API 服务中,使用 network
方法生成 API 请求。
dart
class ApiService extends BaseApiService {
ApiService({BuildContext? buildContext}) : super(buildContext);
@override
String get baseUrl => "https://jsonplaceholder.typicode.com";
Future<dynamic> fetchUsers() async {
return await network(
request: (request) {
// return request.get("/users"); // GET请求
// return request.put("/users", data: {"user": "data"}); // PUT请求
// return request.post("/users", data: {"user": "data"}); // POST请求
// return request.delete("/users/1"); // DELETE请求
return request.get("/users");
},
);
}
}
参数
request
是一个 Dio 实例,因此您可以从该对象调用所有方法。
3. 基础设置
BaseOptions
变量是高度可配置的,允许修改 API 请求设置。
在 API 服务中,可以重写构造函数。
dart
class ApiService extends BaseApiService {
ApiService({BuildContext? buildContext}) : super(buildContext) {
baseOptions = BaseOptions(
receiveTimeout: 10000,
connectTimeout: 5000
);
}
...
单击此处查看所有设置。
4. 添加请求头
可以通过 baseOptions 变量,在每个请求或拦截器上向请求添加头信息。
下面是向请求添加标头的最简单方法。
dart
Future fetchWithHeaders() async => await network(
request: (request) => request.get("/test"),
headers: {
"Authorization": "Bearer aToken123",
"Device": "iPhone"
}
);
您还可以添加 Bearer Token
,如以下示例所示
dart
Future fetchUserWithBearer() async => await network(
request: (request) => request.get("/test"),
bearerToken: "helloworlddd!",
);
或者
dart
Future fetchUsers() async {
return await network(
request: (request) {
request.options.headers = {
"Authorization": "Bearer $token"
};
return request.get("/users");
},
);
}
5. 拦截器
如果您还不熟悉拦截器,请不要担心。它们是管理HTTP请求发送方式的新概念。
简单来说。"拦截器"将拦截请求,允许您在发送请求之前修改请求,在请求完成后处理响应以及如果出现错误会发生什么。
Nylo 允许您向 API 服务添加新的拦截器,如以下示例所示。
dart
class ApiService extends BaseApiService {
ApiService({BuildContext? buildContext}) : super(buildContext);
...
@override
final interceptors = {
LoggingInterceptor: LoggingInterceptor(),
// 添加更多拦截器
// BearerAuthInterceptor: BearerAuthInterceptor(),
};
...
自定义拦截器的示例。
dart
import 'package:nylo_framework/nylo_framework.dart';
class CustomInterceptor extends Interceptor {
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
// options - 发送请求之前修改请求
return super.onRequest(options, handler);
}
@override
void onResponse(Response response, ResponseInterceptorHandler handler) {
// response - 处理响应内容
handler.next(response);
}
@override
void onError(DioError error, ErrorInterceptorHandler handler) {
// error - 处理请求错误
handler.next(err);
}
}
Nylo 上的模版将包含一个 app/networking/dio/intecetors/*
目录。
在此文件夹中,您将找到一个 LoggingInterceptor
类。
app/networking/dio/intecetors/logging_interceptor.dart
文件:
dart
import 'dart:developer';
import 'package:nylo_framework/nylo_framework.dart';
class LoggingInterceptor extends Interceptor {
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
print('REQUEST[${options.method}] => PATH: ${options.path}');
return super.onRequest(options, handler);
}
@override
void onResponse(Response response, ResponseInterceptorHandler handler) {
print(
'RESPONSE[${response.statusCode}] => PATH: ${response.requestOptions
.path}');
print('DATA: ${response.requestOptions.path}');
log(response.data.toString());
handler.next(response);
}
@override
void onError(DioError err, ErrorInterceptorHandler handler) {
print('ERROR[${err.response?.statusCode}] => PATH: ${err.requestOptions
.path}');
handler.next(err);
}
}
6. network方法
network
为我们提供了一种从应用程序发出 HTTP 请求的方法。在 Nylo 中使用 API 服务时,可以使用network
方法。
dart
class ApiService extends BaseApiService {
...
Future<dynamic> fetchUsers() async {
return await network(
request: (request) {
// return request.get("/users"); // GET请求
// return request.put("/users", data: {"user": "data"}); // PUT请求
// return request.post("/users", data: {"user": "data"}); // POST请求
// return request.delete("/users/1"); // DELETE请求
return request.get("/users");
},
);
}
返回类型
有两种方法可以处理来自 HTTP 请求的响应。让我们来看看两者的实际效果,这样做没有对错之分。
- 使用Model Decoders
它们使返回对象变得容易,如以下示例所示。
dart
class ApiService extends BaseApiService {
...
Future<User?> fetchUser() async {
return await network<User>(
request: (request) => request.get("/users/1"),
);
}
config/decoders.dart文件
dart
final modelDecoders = {
User: (data) => User.fromJson(data), // 添加模型并处理对象的返回
//该 `data` 参数将包含 HTTP 响应正文。
// ...
};
在此处了解有关解码器的更多信息
- 使用handleSuccess
handleSuccess: (Response response) {}
参数可用于处理 HTTP 返回值。
仅当 HTTP 响应的状态代码等于 200 时,才调用此方法。
dart
class ApiService extends BaseApiService {
...
// 返回一个对象
Future<User?> findUser() async {
return await network(
request: (request) => request.get("/users/1"),
handleSuccess: (Response response) { // response - Dio响应对象
dynamic data = response.data;
return User.fromJson(data);
}
);
}
// 返回一个字符串
Future<String?> findMessage() async {
return await network(
request: (request) => request.get("/message/1"),
handleSuccess: (Response response) { // response - Dio响应对象
dynamic data = response.data;
if (data['name'] == 'Anthony') {
return "It's Anthony";
}
return "Hello world";
}
);
}
// 返回一个布尔
Future<bool?> updateUser() async {
return await network(
request: (request) => request.put("/user/1", data: {"name": "Anthony"}),
handleSuccess: (Response response) { // response - Dio响应对象
dynamic data = response.data;
if (data['status'] == 'OK') {
return true;
}
return false;
}
);
}
如果 HTTP 响应返回不等于 200 的状态代码,则将调用方法 handleFailure
。
可以为network
提供参数handleFailure: (DioError dioError) {}
, 然后在函数中处理响应。
dart
class ApiService extends BaseApiService {
...
// 返回一个对象
Future<User?> findUser() async {
return await network(
request: (request) => request.get("/users/1"),
handleFailure: (DioError dioError) { // response - Dio错误对象
dynamic data = response.data;
// 处理返回内容
return null;
}
);
}
}
7. 使用 API 服务
当您需要从小部件调用 API 时,Nylo 中有两种不同的方法。
1). 可以创建 API 服务的新实例,然后调用要使用的方法,如以下示例所示。
dart
class _MyHomePageState extends NyState<MyHomePage> {
ApiService _apiService = ApiService();
@override
init() async {
List<User>? users = await _apiService.fetchUsers();
print(users); // List<User>? 实例
...
2). 使用 api
方法,此方法更短,并且通过使用 config/decoders.dart 中的 apiDecoders
变量来工作。
dart
class _MyHomePageState extends NyState<MyHomePage> {
@override
init() async {
User? user = await api<ApiService>((request) => request.fetchUser());
print(user); // User? instance
...
使用 api
方法还允许在请求不成功时处理对用户的 UI 反馈。为此,请将 context
参数添加到 api
,如以下示例所示。
dart
// 组件
...
User _user = User();
@override
Widget build(BuildContext context) {
return Scaffold(
body: MaterialButton(
onPressed: () {
_sendFriendRequest(_user);
},
child: Text("Send Friend Request"),
);
);
}
_sendFriendRequest(User user) async {
bool? successful = await api<ApiService>(
(request) => request.sendFriendRequest(user), context: context
);
}
...
// API服务
class ApiService extends BaseApiService {
...
// Add this
displayError(DioError dioError, BuildContext context) {
showToastNotification(context, title: 'Oops!', description: dioError.message);
}
}
displayError
- 如果请求发生错误(例如 500 状态代码),您可以通过 Toast 通知立即向用户提供反馈。
8. 创建接口服务
要创建更多api_services,例如 user_api_service
,请使用以下命令。
dart run nylo_framework:main make:api_service user
还可以使用该 --model="User"
选项为模型创建 API 服务。
dart run nylo_framework:main make:api_service user --model="User"
这将使用以下方法创建 API 服务。
dart
class UserApiService extends BaseApiService {
...
/// Return a list of users
Future<List<User>?> fetchAll({dynamic query}) async {
return await network<List<User>>(
request: (request) => request.get("/endpoint-path", queryParameters: query),
);
}
/// Find a User
Future<User?> find({required int id}) async {
return await network<User>(
request: (request) => request.get("/endpoint-path/$id"),
);
}
/// Create a User
Future<User?> create({required dynamic data}) async {
return await network<User>(
request: (request) => request.post("/endpoint-path", data: data),
);
}
/// Update a User
Future<User?> update({dynamic query}) async {
return await network<User>(
request: (request) => request.put("/endpoint-path", queryParameters: query),
);
}
/// Delete a User
Future<bool?> delete({required int id}) async {
return await network<bool>(
request: (request) => request.delete("/endpoint-path/$id"),
);
}
}
9. 将 JSON 转换为 models
您可以使用解码器自动解码 JSON,从 API 请求解码到模型。
下面是一个使用 Nylo 解码器实现的 API 请求。
dart
class ApiService extends BaseApiService {
ApiService({BuildContext? buildContext}) : super(buildContext);
Future<User?> fetchUsers() async {
return await network<User>(
request: (request) => request.get("/users"),
);
}
}
fetchUsers
方法将使用泛型处理到模型表示形式的 JSON 转换。
您首先需要将模型添加到文件中 config/decoders.dart
,如下所示。
dart
/// 'config/decoders.dart'文件
final modelDecoders = {
List<User>: (data) => List.from(data).map((json) => User.fromJson(json)).toList(),
User: (data) => User.fromJson(data),
// ...
};
在这里,您可以提供模型的不同表示形式,例如像上面那样的对象或列表。
解码器中的数据参数将包含来自 API 请求的响应正文。
要开始使用解码器,请查看文档的后续章节。