Flutter Http 库 Dio 2.1 正式发布
Dio 是一个强大的 Dart Http 请求库,支持 Restful API、FormData、拦截器、请求取消、Cookie 管理、文件上传 / 下载、超时、自定义适配器等。目前 Dio 在 pub 上综合得分 100 分,排名已上榜 pub 首页(All Tab 下)!同时 Dio 也是 Github 上最受欢迎的 Flutter 第三方库,项目地址:Dio-Github。
在 1.0 发布至今,Dio 受到了大量国内外开发者的关注,并收到了很多肯定和建议。为了让 Dio 功能更强大、让开发者使用起来更容易,我们综合了 1.0 中的各种反馈,对 Dio 进行了一次大的更新,为了让使用者在 1.0 和 2.x 之间有个过渡,我们将 2.0.x-2.1.0 作为预发布版在全网进行了接近两个月的公测。现在,很高兴的告诉大家,2.x 的功能已经收敛、质量已经稳定,因此,今天我们正式发布 Dio 2.x 的第一个稳定版 Dio v2.1.0。
相比 1.x,2.x 在 Restful API、拦截器、FormData 等很多地方都进行了扩展和调整,除了这些,Dio 在 2.x 中还引入 Adapter 层,为 Mock 接口数据和自定义底层网络库提供了支持。整体功能相比 1.x 有了很大的提升,因此我们强烈建议所有 1.x 用户都能升级到 2.1。
Dio V2.1.x 变更列表
Restful API
2.1 中对所有 Restful API 的变化有:
支持 Uri,在 1.x 中,Url 只能是字符串,2.1 中所有 API 都提供了对应支持 Uri 的版本,如 get 方法有 dio.get(…)和 dio.gerUri(…)。
所有方法都支持 queryParameters,2.1 标准化了参数语义,并允许所有请求都可以传 query,而 data 只针对可以提交请求体的方法如 post 作为请求体提交。另外相对于 Uri.queryParameters,我们对 Restful API 中的 queryParameters 的功能做了加强,主要有两个差异:
参数值类型不同;前者只能接受 Map<String, String|Iterable<String>> 类型的参数,而后者可以接受 Map<String, dynamic> 类型,比如:
dio.getUri(Uri(url, queryParameters: {“age”:15})) // 会抛出异常,Uri.queryParameter 的 value 不能是 int 类型
dio.get(url, queryParameters: {“age”:15}); // 这是 OK 的!
编码方式有所差异; Uri.queryParameters 编码方式遵循 Dart SDK 中的规则,而 Restful API 中的 queryParameters 编码方式和 jQuery 一致,如:
dio.options.baseUrl=”http://domain.com/”;
// 下面请求的最终 uri 为:http://domain.com/api?selectedId=1&selectedId=2
Response response = await dio.getUri(
Uri(path: “api”,queryParameters: {“selectedId”: [“1”, “2”],});
);
// 下面请求的最终 uri 为:https://flutterchina.club?selectedId%5B%5D=1&selectedId%5B%5D=2
dio.get(“api”,queryParameters: {“selectedId”: [“1”, “2”], });
支持以 Stream 方式提交数据了;2.1 中可以通过 Stream 的方式来提交二进制数据了,详细的示例可以参考这里。
支持以二进制数组形式接收数据了;1.x 中如果要以二进制形式接收响应数据则需要设置 options.responseType 为 ResponseType.stream 来接收响应流,然后再通过读取响应流来获取完整的二进制内容,而 2.x 中只需要设置为 ResponseType.bytes,则可直接获得响应流的而精致数组。
API 统一添加了 onSendProgress 和 onReceiveProgress 两个回调,用于监听发送数据和接收数据的具体精度,在 1.x 中只有在下载文件和上传 formdata 时才能监听进度,而 2.x 中所有接口都可以了。
拦截器
支持设置多个拦截器;这样我们就可以将一些功能单独抽离,比如打印请求 / 响应日志和 cookie 管理都可以单独封装在一个拦截器中,这样在解耦的同时可以提高代码的可复用度。
2.1 中拦截器是一个队列,拦截器将会按照 FIFO 顺序执行,如果队列中的某个拦截器返回了 Response 或 Error,则请求结束,队列后面的拦截器将不会再被执行。
预置了打印请求 / 响应日志的 LogInterceptor 和管理 cookie 的 CookieManager 拦截器,开发者可以按需使用,如:
dio.interceptors
..add(LogInterceptor(responseBody: false))
..add(CookieManager(CookieJar()));
FormData
1.x 中,在提交 FormData 时会先将 FormData 转成一个二进制数组,然后再提交,这在 FormData 中的数据量比较大时(如包含多个大文件)在上传的过程中会比较占用内存。2.1 中我们队 FormData 进行了增强,给 FormData 添加一个 stream 属性,它可以将 FormData 转为一个 stream,在提交时无需一次性加载到内存。
同时 FormData 也添加了 asBytes()、asBytesAsync()、length 等方法、属性。
Response
Response 中添加了一些关于重定向信息的字段,有 isRedirect、redirects、realUri。
TransFormer
2.x 中对于 DefaultTransformer 添加了一个 jsonDecodeCallback,通过它可以定制 json 解码器,这在 flutter 中非常有用,我们可以通过 compute 方法来在后台进行 json 解码,从而避免在 UI 线程对复杂 json 解码时引起的界面卡顿,详情请见这里。
HttpClientAdapter
HttpClientAdapter 是 Dio 和 HttpClient 之间的桥梁。2.0 抽象出了 adapter 层,可以带来两个主要收益:
实现 Dio 于 HttpClient 的解耦,这样可以方便的切换、定制底层网络库。
可以 Mock 数据;
Dio 实现了一套标准的、强大 API,而 HttpClient 则是真正发起 Http 请求的对象,两者并不是固定的一对一关系,我们完全可以在使用 Dio 时通过其他网络库 (而不仅仅是 dart HttpClient) 来发起网络请求。我们通过 HttpClientAdapter 将 Dio 和 HttpClient 解耦,这样一来便可以自由定制 Http 请求的底层实现,比如,在 Flutter 中我们可以通过自定义 HttpClientAdapter 将 Http 请求转发到 Native 中,然后再由 Native 统一发起请求。再比如,假如有一天 OKHttp 提供了 dart 版,你想使用 OKHttp 发起 http 请求,那么你便可以通过适配器来无缝切换到 OKHttp,而不用改之前的代码。
Dio 使用 DefaultHttpClientAdapter 作为其默认 HttpClientAdapter,DefaultHttpClientAdapter 使用 dart:io:HttpClient 来发起网络请求。
这里 有一个简单的自定义 Adapter 的示例,读者可以参考。另外本项目的自动化测试用例全都是通过一个自定义的 MockAdapter 来模拟服务器返回数据的。
Options
Options 对象包含了对网络请求的配置,在 1.x 中无论是实例配置还是单次请求的配置都使用的是 Options 对象,这样会带来一些二义性,甚至有时会让开发者感到疑惑,比如 Options.baseUrl 属性代表请求基地址,理论上它只应该在实例配置中设置,而不应该出现在每次请求的配置中;再比如 Options.path 属性,它代表请求的相对路径,不应该在实例请求配置中。2.1 中将请求配置分拆成三个类:
类名
作用
BaseOptions
Dio 实例基配置,默认对该 dio 实例的所有请求生效
Options
单次请求配置,可以覆盖 BaseOptions 中的同名属性
RequestOptions
请求的最终配置,是对 Option 和 BaseOptions 合并后的
另外,添加了一些新的配置项:
cookies:可以添加一些公共 cookie
receiveDataWhenStatusError:当响应状态码不是成功状态 (如 404) 时,是否接收响应内容,如果是 false, 则 response.data 将会为 null
maxRedirects: 重定向最大次数。