dio是Flutter中文网开源的一个强大的Dart Http请求库,支持Restful API、FormData、拦截器、请求取消、Cookie管理、文件上传/下载、超时等...

自dio开源至今,收到了大量国内外开发者的反馈,到目前为止,dio在pub仓库得分96分,github dart语言下开源项目排名已上升到前20,dio现在也是flutter第三方package中star数最多的。在dio开源的两个月中,已迭代了18个小版本,国内外有多家公司的Flutter APP正在使用dio,已通过了大量的实战验证,已经在AppStore上架的APP典型代表是gitme:

Gitme是一个强大的github客户端APP,它使用dio作为http client,除了正常的http请求之外,有一个最大的特点是gitme通过dio拦截器,实现了APP内统一、隔离的缓存层,完全和上层ui解耦。您可以下载体验一下Gitme。如有必要,我会单独出一篇文章详细介绍一下如何使用dio拦截器实现离线缓存,大家如果有兴趣可以在评论中反馈。

所以,今天,我们正式发布dio的第一个稳定版本1.0。下面,我们全面的介绍一下dio 1.0的功能及使用。

建议dio的老用户都升级到1.0正式版,并同时感谢你们在dio项目初期的支持,没有你们的反馈与建议,dio稳定版不会这么快发布。

dio

dio是一个强大的Dart Http请求库,支持Restful API、FormData、拦截器、请求取消、Cookie管理、文件上传/下载、超时等...

添加依赖

dependencies:

dio: ^x.x.x // 请使用pub上的最新版本

一个极简的示例

import 'package:dio/dio.dart';

Dio dio = new Dio();

Response response=await dio.get("https://www.google.com/");

print(response.data);

最近更新

文件上传支持数组。

支持http状态码被认为对应成功或失败的自定义判断。

添加清空拦截器队列API Clear()。

内容列表

示例

发起一个 GET 请求 :

Response response;

response=await dio.get("/test?id=12&name=wendu")

print(response.data.toString());

// 请求参数也可以通过对象传递,上面的代码等同于:

response=await dio.get("/test",data:{"id":12,"name":"wendu"})

print(response.data.toString());

发起一个 POST 请求:

response=await dio.post("/test",data:{"id":12,"name":"wendu"})

发起多个并发请求:

response= await Future.wait([dio.post("/info"),dio.get("/token")]);

下载文件:

response=await dio.download("https://www.google.com/","./xx.html")

发送 FormData:

FormData formData = new FormData.from({

"name": "wendux",

"age": 25,

});

response = await dio.post("/info", data: formData)

通过FormData上传多个文件:

FormData formData = new FormData.from({

"name": "wendux",

"age": 25,

"file1": new UploadFileInfo(new File("./upload.txt"), "upload1.txt"),

"file2": new UploadFileInfo(new File("./upload.txt"), "upload2.txt"),

// 支持文件数组上传

"files": [

new UploadFileInfo(new File("./example/upload.txt"), "upload.txt"),

new UploadFileInfo(new File("./example/upload.txt"), "upload.txt")

]

});

response = await dio.post("/info", data: formData)

…你可以在这里获取所有示例代码.

Dio APIs

创建一个Dio实例,并配置它

你可以使用默认配置或传递一个可选 Options参数来创建一个Dio实例 :

Dio dio = new Dio; // 使用默认配置

// 配置dio实例

dio.options.baseUrl="https://www.xx.com/api"

dio.options.connectTimeout = 5000; //5s

dio.options.receiveTimeout=3000;

// 或者通过传递一个 `options`来创建dio实例

Options options= new Options(

baseUrl:"https://www.xx.com/api",

connectTimeout:5000,

receiveTimeout:3000

);

Dio dio = new Dio(options);

Dio实例的核心API是 :

Future request(String path, {data, Options options,CancelToken cancelToken})

response=await request("/test", data: {"id":12,"name":"xx"}, new Options(method:"GET"));

请求方法别名

为了方便使用,Dio提供了一些其它的Restful API, 这些API都是request的别名。

Future get(path, {data, Options options,CancelToken cancelToken})

Future post(path, {data, Options options,CancelToken cancelToken})

Future put(path, {data, Options options,CancelToken cancelToken})

Future delete(path, {data, Options options,CancelToken cancelToken})

Future head(path, {data, Options options,CancelToken cancelToken})

Future put(path, {data, Options options,CancelToken cancelToken})

Future path(path, {data, Options options,CancelToken cancelToken})

Future download(String urlPath, savePath,

**{OnDownloadProgress onProgress, data, bool flush: false, Options options,CancelToken cancelToken})**

请求配置

下面是所有的请求配置选项。 如果请求method没有指定,则默认为GET :

{

/// Http method.

String method;

/// 请求基地址,可以包含子路径,如: "https://www.google.com/api/".

String baseUrl;

/// Http请求头.

Map headers;

/// 连接服务器超时时间,单位是毫秒.

int connectTimeout;

/// 响应流上前后两次接受到数据的间隔,单位为毫秒。如果两次间隔超过[receiveTimeout],

/// [Dio] 将会抛出一个[DioErrorType.RECEIVE_TIMEOUT]的异常.

/// 注意: 这并不是接收数据的总时限.

int receiveTimeout;

/// 请求数据,可以是任意类型.

var data;

/// 请求路径,如果 `path` 以 "http(s)"开始, 则 `baseURL` 会被忽略; 否则,

/// 将会和baseUrl拼接出完整的的url.

String path="";

/// 请求的Content-Type,默认值是[ContentType.JSON].

/// 如果您想以"application/x-www-form-urlencoded"格式编码请求数据,

/// 可以设置此选项为 `ContentType.parse("application/x-www-form-urlencoded")`, 这样[Dio]

/// 就会自动编码请求体.

ContentType contentType;

/// [responseType] 表示期望以那种格式(方式)接受响应数据。

/// 目前 [ResponseType] 接受三种类型 `JSON`, `STREAM`, `PLAIN`.

///

/// 默认值是 `JSON`, 当响应头中content-type为"application/json"时,dio 会自动将响应内容转化为json对象。

/// 如果想以二进制方式接受响应数据,如下载一个二进制文件,那么可以使用 `STREAM`.

///

/// 如果想以文本(字符串)格式接收响应数据,请使用 `PLAIN`.

ResponseType responseType;

/// `validateStatus` 决定http响应状态码是否被dio视为请求成功, 返回`validateStatus`

/// 返回`true` , 请求结果就会按成功处理,否则会按失败处理.

ValidateStatus validateStatus;

/// 用户自定义字段,可以在 [Interceptor]、[Transformer] 和 [Response] 中取到.

Map extra;

}

这里有一个完成的示例.

响应数据

当请求成功时会返回一个Response对象,它包含如下字段:

{

/// 响应数据,可能已经被转换了类型, 详情请参考Options中的[ResponseType].

var data;

/// 响应头

HttpHeaders headers;

/// 本次请求信息

Options request;

/// Http status code.

int statusCode;

/// 响应对象的自定义字段(可以在拦截器中设置它),调用方可以在`then`中获取.

Map extra;

}

示例如下:

Response response=await dio.get("https://www.google.com");

print(response.data);

print(response.headers);

print(response.request);

print(statusCode);

拦截器

每一个 Dio 实例都有一个请求拦截器 RequestInterceptor 和一个响应拦截器 ResponseInterceptor, 通过拦截器你可以在请求之前或响应之后(但还没有被 then 或 catchError处理)做一些统一的预处理操作。

dio.interceptor.request.onSend = (Options options){

// 在请求被发送之前做一些事情

return options; //continue

// 如果你想完成请求并返回一些自定义数据,可以返回一个`Response`对象或返回`dio.resolve(data)`。

// 这样请求将会被终止,上层then会被调用,then中返回的数据将是你的自定义数据data.

//

// 如果你想终止请求并触发一个错误,你可以返回一个`DioError`对象,或返回`dio.reject(errMsg)`,

// 这样请求将被中止并触发异常,上层catchError会被调用。

}

dio.interceptor.response.onSuccess = (Response response) {

// 在返回响应数据之前做一些预处理

return response; // continue

};

dio.interceptor.response.onError = (DioError e){

// 当请求失败时做一些预处理

return e;//continue

}

如果你想移除拦截器,你可以将它们置为null:

dio.interceptor.request.onSend=null;

dio.interceptor.response.onSuccess=null;

dio.interceptor.response.onError=null;

完成和终止请求/响应

在所有拦截器中,你都可以改变请求执行流, 如果你想完成请求/响应并返回自定义数据,你可以返回一个 Response 对象或返回 dio.resolve(data)的结果。 如果你想终止(触发一个错误,上层catchError会被调用)一个请求/响应,那么可以返回一个DioError 对象或返回 dio.reject(errMsg) 的结果.

dio.interceptor.request.onSend = (Options options){

return dio.resolve("fake data")

}

Response response= await dio.get("/test");

print(response.data);//"fake data"

拦截器中支持异步任务

拦截器中不仅支持同步任务,而且也支持异步任务, 下面是在请求拦截器中发起异步任务的一个实例:

dio.interceptor.request.onSend = (Options options) async{

//...If no token, request token firstly.

Response response = await dio.get("/token");

//Set the token to headers

options.headers["token"] = response.data["data"]["token"];

return options; //continue

}

Lock/unlock 拦截器

你可以通过调用拦截器的 lock()/unlock 方法来锁定/解锁拦截器。一旦请求/响应拦截器被锁定,接下来的请求/响应将会在进入请求/响应拦截器之前排队等待,直到解锁后,这些入队的请求才会继续执行(进入拦截器)。这在一些需要串行化请求/响应的场景中非常实用,后面我们将给出一个示例。

tokenDio=new Dio(); //Create a new instance to request the token.

tokenDio.options=dio;

dio.interceptor.request.onSend = (Options options) async{

// If no token, request token firstly and lock this interceptor

// to prevent other request enter this interceptor.

dio.interceptor.request.lock();

// We use a new Dio(to avoid dead lock) instance to request token.

Response response = await tokenDio.get("/token");

//Set the token to headers

options.headers["token"] = response.data["data"]["token"];

dio.interceptor.request.unlock()

return options; //continue

}

Clear()

你也可以调用拦截器的clear()方法来清空等待队列。

别名

当请求拦截器被锁定时,接下来的请求将会暂停,这等价于锁住了dio实例,因此,Dio示例上提供了请求拦截器lock/unlock的别名方法:

dio.lock() == dio.interceptor.request.lock()

dio.unlock() == dio.interceptor.request.unlock()

dio.clear() == dio.interceptor.request.clear()

示例

假设这么一个场景:出于安全原因,我们需要给所有的请求头中添加一个csrfToken,如果csrfToken不存在,我们先去请求csrfToken,获取到csrfToken后,再发起后续请求。 由于请求csrfToken的过程是异步的,我们需要在请求过程中锁定后续请求(因为它们需要csrfToken), 直到csrfToken请求成功后,再解锁,代码如下:

dio.interceptor.request.onSend = (Options options) {

print('send request:path:${options.path},baseURL:${options.baseUrl}');

if (csrfToken == null) {

print("no token,request token firstly...");

//lock the dio.

dio.lock();

return tokenDio.get("/token").then((d) {

options.headers["csrfToken"] = csrfToken = d.data['data']['token'];

print("request token succeed, value: " + d.data['data']['token']);

print('continue to perform request:path:${options.path},baseURL:${options.path}');

return options;

}).whenComplete(() => dio.unlock()); // unlock the dio

} else {

options.headers["csrfToken"] = csrfToken;

return options;

}

};

完整的示例代码请点击 这里.

错误处理

当请求过程中发生错误时, Dio 会包装 Error/Exception 为一个 DioError:

try {

//404

await dio.get("https://wendux.github.io/xsddddd");

} on DioError catch(e) {

// The request was made and the server responded with a status code

// that falls out of the range of 2xx and is also not 304.

if(e.response) {

print(e.response.data)

print(e.response.headers)

print(e.response.request)

} else{

// Something happened in setting up or sending the request that triggered an Error

print(e.request)

print(e.message)

}

}

DioError 字段

{

/// 响应信息, 如果错误发生在在服务器返回数据之前,它为 `null`

Response response;

/// 错误描述.

String message;

/// 错误类型,见下文

DioErrorType type;

/// 错误栈信息,可能为null

StackTrace stackTrace;

}

DioErrorType

enum DioErrorType {

/// Default error type, usually occurs before connecting the server.

DEFAULT,

/// When opening url timeout, it occurs.

CONNECT_TIMEOUT,

/// Whenever more than [receiveTimeout] (in milliseconds) passes between two events from response stream,

/// [Dio] will throw the [DioError] with [DioErrorType.RECEIVE_TIMEOUT].

///

/// Note: This is not the receiving time limitation.

RECEIVE_TIMEOUT,

/// When the server response, but with a incorrect status, such as 404, 503...

RESPONSE,

/// When the request is cancelled, dio will throw a error with this type.

CANCEL

}

使用application/x-www-form-urlencoded编码

默认情况下, Dio 会将请求数据(除过String类型)序列化为 JSON. 如果想要以 application/x-www-form-urlencoded格式编码, 你可以显式设置contentType :

//Instance level

dio.options.contentType=ContentType.parse("application/x-www-form-urlencoded");

//or works once

dio.post("/info",data:{"id":5}, options: new Options(contentType:ContentType.parse("application/x-www-form-urlencoded")))

这里有一个示例.

FormData

Dio支持发送 FormData, 请求数据将会以 multipart/form-data方式编码, FormData中可以一个或多个包含文件 .

FormData formData = new FormData.from({

"name": "wendux",

"age": 25,

"file": new UploadFileInfo(new File("./example/upload.txt"), "upload.txt")

});

response = await dio.post("/info", data: formData)

注意: 只有 post 方法支持发送 FormData.

这里有一个完整的示例.

转换器

转换器Transformer 用于对请求数据和响应数据进行编解码处理。Dio实现了一个默认转换器DefaultTransformer作为默认的 Transformer. 如果你想对请求/响应数据进行自定义编解码处理,可以提供自定义转换器,通过 dio.transformer设置。

请求转换器 Transformer.transformRequest(...) 只会被用于 'PUT'、 'POST'、 'PATCH'方法,因为只有这些方法才可以携带请求体(request body)。但是响应转换器 Transformer.transformResponse() 会被用于所有请求方法的返回数据。

执行流

虽然在拦截器中也可以对数据进行预处理,但是转换器主要职责是对请求/响应数据进行编解码,之所以将转化器单独分离,一是为了和拦截器解耦,二是为了不修改原始请求数据(如果你在拦截器中修改请求数据(options.data),会覆盖原始请求数据,而在某些时候您可能需要原始请求数据). Dio的请求流是:

请求拦截器 >> 请求转换器 >> 发起请求 >> 响应转换器 >> 响应拦截器 >> 最终结果。

这是一个自定义转换器的示例.

设置Http代理

Dio 是使用 HttpClient发起的http请求,所以你可以通过配置 httpClient来支持代理,示例如下:

dio.onHttpClientCreate = (HttpClient client) {

client.findProxy = (uri) {

//proxy all request to localhost:8888

return "PROXY localhost:8888";

};

// 你也可以自己创建一个新的HttpClient实例返回。

// return new HttpClient(SecurityContext);

};

完整的示例请查看这里.

请求取消

你可以通过 cancel token 来取消发起的请求:

CancelToken token = new CancelToken();

dio.get(url, cancelToken: token)

.catchError((DioError err){

if (CancelToken.isCancel(err)) {

print('Request canceled! '+ err.message)

}else{

// handle error.

}

})

// cancel the requests with "cancelled" message.

token.cancel("cancelled");

注意: 同一个cancel token 可以用于多个请求,当一个cancel token取消时,所有使用该cancel token的请求都会被取消。

完整的示例请参考取消示例.

Cookie管理

你可以通过 cookieJar 来自动管理请求/响应cookie.

dio cookie 管理 API 是基于开源库 cookie_jar.

你可以创建一个CookieJar 或 PersistCookieJar 来帮您自动管理cookie, dio 默认使用 CookieJar , 它会将cookie保存在内存中。 如果您想对cookie进行持久化, 请使用 PersistCookieJar , 示例代码如下:

var dio = new Dio();

dio.cookieJar=new PersistCookieJar("./cookies");

PersistCookieJar 实现了RFC中标准的cookie策略. PersistCookieJar 会将cookie保存在文件中,所以 cookies 会一直存在除非显式调用 delete 删除.

Copyright & License

此开源项目为Flutter中文网(https://flutterchina.club) 授权 ,license 是 MIT. 如果您喜欢,欢迎star.

Flutter中文网开源项目计划

开发一系列Flutter SDK之外常用(实用)的Package、插件,丰富Flutter第三方库,为Flutter生态贡献来自中国开发者的力量。所有项目将发布在 Github Flutter中文网 Organization ,所有源码贡献者将加入到我们的Organization,成为成员. 目前社区已有几个开源项目开始公测,欢迎您加入开发或测试,详情请查看: Flutter中文网开源项目。 如果您想加入到“开源项目计划”, 请发邮件到824783146@qq.com, 并附上自我介绍(个人基本信息+擅长/关注技术)。

Features and bugs

Please file feature requests and bugs at the issue tracker.

flutterdio_强大的Flutter http请求库dio相关推荐

  1. Flutter网络请求库DIO入门文档,实战案例

    var request = await httpClient.getUrl(Uri.parse(url)); var response = await request.close(); if (res ...

  2. Flutter网络请求库DIO入门文档(1),android开发网

    }); response = await dio.post("http/test/upload", data: formData); //上传多个文件 formData = For ...

  3. Flutter网络请求库DIO的使用

    1. 导入dio包 目前dio库的最新版本是3.0.1,同使用其他三方库一样,Flutter中使用dio库同样需要配置pubspec.yaml文件. dependencies:flutter:sdk: ...

  4. Flutter 网络请求框架dio使用详解

    前言 dio是一款Flutter 网络请求框架,在GitHub上目前有超过5.9k个star.由国人(Flutter中文网)开发,所以中文文档非常完善. 这里copy了dio官方的文档,便于自己开发时 ...

  5. Flutter 网络请求库http

    http 集成http库 https://pub.dartlang.org/packages/http 添加依赖 dependencies:http: ^0.12.0 安装 flutter packa ...

  6. dio java,Flutter基础(十一)网络请求(Dio)与JSON数据解析

    本文首发于微信公众号「后厂技术官」 前言 在Android开发中如果我们想要请求网络,可以使用HttpClent.HttpURLConnection,但在项目中一般都会使用OkHttp和Retrofi ...

  7. Flutter网络请求方式总结

    转载于:https://www.jianshu.com/p/59fc5ed37453 前言 编写一个 App,最离不开的就是网络请求了.在Android 原生中,网络请求库一直在更新,网络请求库甚多: ...

  8. Flutter实战之网络请求框架Dio入门使用

    本篇博文涉及到的demo很简单,就是通过调用天气查询接口来显示城市的天气信息.通过本demo可以了解: 1.CityPicker的简单使用 2.Dio网络请求库的简单使用 3.Flutter对json ...

  9. python网络爬虫教程(四):强大便捷的请求库requests详解与编程实战

    上一章中,我们了解了urllib的基本用法,详情可浏览如下链接python网络爬虫教程(三):详解urllib库,但其中确实有不方便的地方,为此,我们可以使用更方便更简洁的HTTP请求库request ...

最新文章

  1. 我收藏的谷歌和阿里大佬的刷题笔记
  2. 图神经网络(GNN)的简介
  3. hdu5389(DP)
  4. mybatis分页查询
  5. matlab怎么计算行列式,Matlab 线性代数(一)–行列式与方程组求解 | 学步园
  6. [网络流24题]圆桌问题
  7. excel柱状图堆叠图显示总和_Excel堆积柱形图同时显示合计值和构成值的方法介绍...
  8. 如何利用php下载文件_PHP使用文件流下载文件方法
  9. c# 小写金额转大写
  10. 全排列、排列组合(去重区别)
  11. win10 不能使用 ps3相机
  12. 17款现代风格的免费英文字体,分享给设计师们
  13. 最大奇约数(c++实现)
  14. 如何避开PPT演讲的几个误区(上)
  15. 自控带宽频率等相关介绍
  16. 致所有看到这段话的朋友们
  17. 一次国产系统与国外系统对比,CCTV 令人无语
  18. 匹兹堡大学计算机科学,匹兹堡大学计算机科学硕士排名第63(2020年TFE Times排名)...
  19. linux开放目录注意
  20. 网页导出Excel文件并下载

热门文章

  1. 戴尔 DELL 游戏笔记本电脑 - Windows 10 关闭触摸板
  2. Centos7 修改SSH端口,以及修改密码
  3. 反思|开启B站少女心模式,探究APP换肤机制的设计与实现
  4. 编程题目+数据库题目总结(3)
  5. python数据分析(三)——pandas缺失值处理
  6. 华为云服务器重装java环境
  7. 关于SQL中的ASSERTION(某单位想举行一个小型的联谊会……)
  8. 微信小程序动态添加class样式
  9. USACO 1月 2021-2022 January Contest Bronze 题解
  10. 多人聊天功能代码php,PHP+swoole实现简单多人在线聊天群发效果