注册

flutter 极简的网络请求 - Retrofit 文档记录

前言

对于Retrofit插件说实话之前是不太了解的,后来偶然发现了它,感觉还是比较惊艳的。主要工作流程就是注解、生成,通过定义简化通用请求方法的繁杂工作。(ps: json_serializablefreezed 和 最新的Riverpod也是类似的工作方式,但Riverpod理解要稍微复杂一些。)

优秀插件太多感觉都有点看不完了,但是一聊到能减少重()复()工()作()那高低肯定是要上车了。 (●'◡'●)

插件Git地址:retorfit.dart

一、Retrofit 文档记录

主要目的还是记录一下,方便后续使用的时候查看。

1、添加插件引用

dependencies:
dio: any
retrofit: '>=4.0.0 <5.0.0'
logger: any #for logging purpose
json_annotation: ^4.8.1

dev_dependencies:
retrofit_generator: '>=7.0.0 <8.0.0' // required dart >=2.19
build_runner: '>=2.3.0 <4.0.0'
json_serializable: ^6.6.2

2、定义请求使用

import 'package:dio/dio.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:retrofit/retrofit.dart';

part 'example.g.dart';

@RestApi(
// 请求域名
baseUrl: 'https://5d42a6e2bc64f90014a56ca0.mockapi.io/api/v1/',
// 数据解析方式,默认为json
parser: Parser.JsonSerializable,
)
abstract class RestClient {
// 标准的构建方式
// dio: 传入发起网络请求的对象
// baseUrl: 请求域名,优先级高于注解
factory RestClient(Dio dio, {String baseUrl}) = _RestClient;

// 1、添加请求方式注解,接口地址
// 2、定义返回值类型(可以是任意类型,也可以是定义好的model),请求方法名,请求参数(后面会提到)
@GET('/tasks')
Future<List<Task>> getTasks();
}

example.g.dart 是脚本生成的具体实现文件;

@RestApi(baseUrl:...) 添加注解及部分配置参数;

Future<List<Task>> getTasks(...) 定义请求的返回值、参数值、请求类型与接口地址;

这个文件请求方法配置,按规范书写就可以了。

3、执行编译脚本

# dart
dart pub run build_runner build

# flutter
flutter pub run build_runner build

// 个人更建议使用 watch 命令
// 该命令监听输入,可以实时编译最新的代码,不用每次修改之后重复使用 build 了
flutter pub run build_runner watch

4、基本使用

import 'package:dio/dio.dart';
import 'package:logger/logger.dart';
import 'package:retrofit_example/example.dart';

final logger = Logger();

void main(List<String> args) {
final dio = Dio(); // Provide a dio instance
dio.options.headers['Demo-Header'] = 'demo header'; // config your dio headers globally
final client = RestClient(dio);

client.getTasks().then((it) => logger.i(it));
}

5、更多的请求方式

  @GET('/tasks/{id}')
Future<Task> getTask(@Path('id') String id);

@GET('/demo')
Future<String> queries(@Queries() Map<String, dynamic> queries);

@GET('https://httpbin.org/get')
Future<String> namedExample(
@Query('apikey') String apiKey,
@Query('scope') String scope,
@Query('type') String type,
@Query('from') int from);

@PATCH('/tasks/{id}')
Future<Task> updateTaskPart(
@Path() String id, @Body() Map<String, dynamic> map);

@PUT('/tasks/{id}')
Future<Task> updateTask(@Path() String id, @Body() Task task);

@DELETE('/tasks/{id}')
Future<void> deleteTask(@Path() String id);

@POST('/tasks')
Future<Task> createTask(@Body() Task task);

@POST('http://httpbin.org/post')
Future<void> createNewTaskFromFile(@Part() File file);

@POST('http://httpbin.org/post')
@FormUrlEncoded()
Future<String> postUrlEncodedFormData(@Field() String hello);

6、在方法中额外添加请求头

  @GET('/tasks')
Future<Task> getTasks(@Header('Content-Type') String contentType);

-- or --

import 'package:dio/dio.dart' hide Headers;

@GET('/tasks')
@Headers(<String, dynamic>{
'Content-Type': 'application/json',
'Custom-Header': 'Your header',
})
Future<Task> getTasks();

官方后续文档就不在这里复述了,下面记录一下我自己的使用方式。

二、Retrofit 个人使用

如官方文档所述,Retrofit的使用本就十分简单,这里更多的是对请求使用的归纳。

1、创建请求体

创建文件api_client.dart,该文件主要是对请求方法的编写。

...
@RestApi()
abstract class ApiClient {
factory ApiClient(Dio dio, {String baseUrl}) = _ApiClient;
// 定义请求方法
...
}

2、创建dio请求拦截

创建文件interceptor.dart,文件主要是对发起请求响应结果的通用处理,简化我们在使用过程中,重复的处理公共模块。


class NetInterceptor extends Interceptor {
NetInterceptor();

@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
// 在这里可以配置请求头,设置公共参数
final token = UserService.to.token.token;
if (token.isNotEmpty) {
options.headers['Authorization'] = token;
}
handler.next(options);
}

@override
void onResponse(Response response, ResponseInterceptorHandler handler) {
// 预处理请求返回结果,处理通用的错误信息
// 包括不限于数据格式错误、用户登录失效、 需单独处理的额外约定错误码
Map dataMap;
if (response.data is Map) {
dataMap = response.data;
} else if (response.data is String) {
dataMap = jsonDecode(response.data);
} else {
dataMap = {'code': 200, 'data': response.data, 'message': 'success'};
}

if (dataMap['code'] != 200) {
if (dataMap['code'] == 402 || dataMap['code'] == 401) {
// _ref.read(eventBusProvider).fire(AppNeedToLogin());
}
handler.reject(
DioError(
requestOptions: response.requestOptions,
error: dataMap['message'],
),
true,
);
return;
}
response.data = dataMap['result'];
handler.next(response);
}
}

3、独立请求参数类

创建文件params.dart,文件主要目的是存放请求类型参数(毕竟官方推荐使用具体类型作为结构参数,非Map),当然也可以直接使用我们请求结果的数据模型作为请求参数(但是不是所有的方法都合适),简单的参数还是不用写这,个人感觉还是太复杂了,不够简洁。

具体没啥说的,直接使用json_serializable就可以了,当然也可以手写,这里推荐一下 VS Code插件 - Dart Data Class Generator,直接定义好属性之后直接通过提示扩展对应的方法就好了。

import 'package:json_annotation/json_annotation.dart';
part 'params.g.dart';

@JsonSerializable()
class TokenParams {
@JsonKey(name: 'client_id')
final String clientId;

TokenParams(this.clientId);
factory TokenParams.fromJson(Map<String, Object?> json) =>
_$TokenParamsFromJson(json);
Map<String, dynamic> toJson() => _$TokenParamsToJson(this);
}

4、添加请求桥接(独立基础请求配置)

创建实际请求类repository.dart,简化实际使用


class NetRepository {
/// 独立请求体
static ApiClient client = ApiClient(
Dio(BaseOptions())
..interceptors.addAll([
LogInterceptor(
requestBody: true,
responseBody: true,
),
NetInterceptor(),
]),
baseUrl: _devDomain.host,
);

/// 如果域名不一致可以独立创建,方便区分
static ApiClient user...
static ApiClient company...

}

final _devDomain = AppDomain(
host: 'https://api.apiopen.top/api',
pcHost: 'http://www.xxx.com ',
);

// 定义域名配置,用类的形式只是为了更好的管理和使用
// 当然这里也可以直接换成枚举、常量字符串等等,看个人编写习惯
class AppDomain {
/// 接口域名
final String host;

/// 电脑端地址
final String pcHost;

/// final String host1;
/// final String host2;
/// ...

AppDomain({
required this.host,
required this.pcHost,
});
}

5、使用案例

这里是搬用上一篇 一站式刷新和加载 的使用场景,其他地方放使用类似。


@override
FutureOr fetchData(int page) async {
try {
final data = await NetRepository.client.videoList(page, 20);
await Future.delayed(const Duration(seconds: 1));
if (tag) {
endLoad(data.list as List<VideoList>, maxCount: data.total);
} else {
tag = true;
endLoad([], maxCount: data.total);
}
} catch (e) {
formatError(e);
}
}

总结

如果使用这个请求库的话,可以极大的简化我们样板式代码的书写,还是值得推荐的。 一切的一切就是都是为了更简单,也算是为了尽量少写没用的代码而努力。

毕竟不想当将军的士兵不是好士兵,不想写代码的程序猿才是好猿。 ( ̄▽ ̄)"

附Demo地址: boomcx/template_getx


作者:佚名啊
链接:https://juejin.cn/post/7244358444349128763
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

0 个评论

要回复文章请先登录注册