dio 3.0.9

  • Readme
  • Changelog
  • Example
  • Installing
  • 100

Language: English | 中文简体

dio #

build status Pub support

Dart的功能强大的Http客户端,支持拦截器,全局配置,FormData,请求取消,文件下载,超时等.

Get started #

Add dependency #

dependencies:
  dio: 3.x #latest version

为了支持Flutter Web,v3.x被大量重构,因此与3.x版本不兼容.有关更新的详细列表,请参见此处 .

Super simple to use #

import 'package:dio/dio.dart';
void getHttp() async {
  try {
    Response response = await Dio().get("http://www.google.com");
    print(response);
  } catch (e) {
    print(e);
  }
}

awesome-dio #

与dio相关的精选事物的精选列表.

Plugins #

PluginsStatusDescription
dio_cookie_managerPubDio的Cookie经理
dio_http2_adapterPub一个支持Http / 2.0的Dio HttpClientAdapter
dio_flutter_transformerPub一个专门用于颤振的Dio转换器,通过它,json解码将在后台具有compute功能.
dio_http_cachePub Dio的缓存库,例如Android中的Rxcache . dio-http-cache使用sqflite作为磁盘缓存,并使用LRU策略作为内存缓存.
retrofitPubretrofit.dart是使用source_gen的dio客户端生成器,其灵感来自Chopper和Retrofit.

欢迎在此处提交Dio的第三方插件和相关库.

Table of contents #

Examples #

执行GET请求:

Response response;
Dio dio = new Dio();
response = await dio.get("/test?id=12&name=wendu");
print(response.data.toString());
// Optionally the request above could also be done as
response = await dio.get("/test", queryParameters: {"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");

获取响应流:

Response<ResponseBody> rs = await Dio().get<ResponseBody>(url,
 options: Options(responseType: ResponseType.stream), // set responseType to `stream`
);
print(rs.data.stream); //response stream

获取字节响应:

Response<List<int>> rs = await Dio().get<List<int>>(url,
 options: Options(responseType: ResponseType.bytes), // // set responseType to `bytes`
);
print(rs.data); // List<int>

发送FormData:

FormData formData = new FormData.fromMap({
    "name": "wendux",
    "age": 25,
  });
response = await dio.post("/info", data: formData);

通过FormData将多个文件上传到服务器:

FormData.fromMap({
    "name": "wendux",
    "age": 25,
    "file": await MultipartFile.fromFile("./text.txt",filename: "upload.txt"),
    "files": [
      await MultipartFile.fromFile("./text1.txt", filename: "text1.txt"),
      await MultipartFile.fromFile("./text2.txt", filename: "text2.txt"),
    ]
});
response = await dio.post("/info", data: formData);

监听上传进度:

response = await dio.post(
  "http://www.dtworkroom.com/doris/1/2.0.0/test",
  data: {"aa": "bb" * 22},
  onSendProgress: (int sent, int total) {
    print("$sent $total");
  },
);

按流发布二进制数据:

// Binary data
List<int> postData = <int>[...];
await dio.post(
  url,
  data: Stream.fromIterable(postData.map((e) => [e])), //create a Stream<List<int>>
  options: Options(
    headers: {
      Headers.contentLengthHeader: postData.length, // set content-length
    },
  ),
);

…您可以在此处找到所有示例代码.

Dio APIs #

Creating an instance and set default configs. #

您可以使用可选的BaseOptions对象创建Dio实例:

Dio dio = new Dio(); // with default Options

// Set default configs
dio.options.baseUrl = "https://www.xx.com/api";
dio.options.connectTimeout = 5000; //5s
dio.options.receiveTimeout = 3000;

// or new Dio with a BaseOptions instance.
BaseOptions options = new BaseOptions(
    baseUrl: "https://www.xx.com/api",
    connectTimeout: 5000,
    receiveTimeout: 3000,
);
Dio dio = new Dio(options);

Dio实例中的核心API是:

Future

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

Request method aliases #

为了方便起见,已为所有受支持的请求方法提供了别名.

Future

Future

Future

Future

Future

Future

Future

Future

Request Options #

Options类描述了http请求信息和配置. 每个Dio实例都有一个针对自己发出的所有请求的基本配置,当发出单个请求时,我们可以使用[Options]覆盖基本配置. [BaseOptions]声明如下:

{
  /// Http method.
  String method;

  /// Request base url, it can contain sub path, like: "https://www.google.com/api/".
  String baseUrl;

  /// Http request headers.
  Map<String, dynamic> headers;

   /// Timeout in milliseconds for opening  url.
  int connectTimeout;

   ///  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.
  int receiveTimeout;

  /// Request data, can be any type.
  T data;

  /// If the `path` starts with "http(s)", the `baseURL` will be ignored, otherwise,
  /// it will be combined and then resolved with the baseUrl.
  String path="";

  /// The request Content-Type. The default value is "application/json; charset=utf-8".
  /// If you want to encode request body with "application/x-www-form-urlencoded",
  /// you can set [Headers.formUrlEncodedContentType], and [Dio]
  /// will automatically encode the request body.
  String contentType;

  /// [responseType] indicates the type of data that the server will respond with
  /// options which defined in [ResponseType] are `JSON`, `STREAM`, `PLAIN`.
  ///
  /// The default value is `JSON`, dio will parse response string to json object automatically
  /// when the content-type of response is "application/json".
  ///
  /// If you want to receive response data with binary bytes, for example,
  /// downloading a image, use `STREAM`.
  ///
  /// If you want to receive the response data with String, use `PLAIN`.
  ResponseType responseType;

  /// `validateStatus` defines whether the request is successful for a given
  /// HTTP response status code. If `validateStatus` returns `true` ,
  /// the request will be perceived as successful; otherwise, considered as failed.
  ValidateStatus validateStatus;

  /// Custom field that you can retrieve it later in [Interceptor]、[Transformer] and the   [Response] object.
  Map<String, dynamic> extra;
  
  /// Common query parameters
  Map<String, dynamic /*String|Iterable<String>*/ > queryParameters;  

}

有一个完整的例子在这里 .

Response Schema #

请求的响应包含以下信息.

{
  /// Response body. may have been transformed, please refer to [ResponseType].
  T data;
  /// Response headers.
  Headers headers;
  /// The corresponding request info.
  Options request;
  /// Http status code.
  int statusCode;
  /// Whether redirect 
  bool isRedirect;  
  /// redirect info    
  List<RedirectInfo> redirects ;
  /// Returns the final real request uri (maybe redirect). 
  Uri realUri;    
  /// Custom field that you can retrieve it later in `then`.
  Map<String, dynamic> extra;
}

请求成功后,您将收到如下响应:

Response response = await dio.get("https://www.google.com");
print(response.data);
print(response.headers);
print(response.request);
print(response.statusCode);

Interceptors #

对于每个dio实例,我们可以添加一个或多个拦截器,通过它们我们可以拦截请求或响应, thenthencatchError处理.

dio.interceptors.add(InterceptorsWrapper(
    onRequest:(RequestOptions options) async {
     // Do something before request is sent
     return options; //continue
     // If you want to resolve the request with some custom data,
     // you can return a `Response` object or return `dio.resolve(data)`.
     // If you want to reject the request with a error message,
     // you can return a `DioError` object or return `dio.reject(errMsg)`
    },
    onResponse:(Response response) async {
     // Do something with response data
     return response; // continue
    },
    onError: (DioError e) async {
     // Do something with response error
     return  e;//continue
    }
));

Resolve and reject the request #

在所有拦截器中,您都可以干扰它们的执行流程. 如果要使用一些自定义数据解决请求/响应,则可以返回Response对象或返回dio.resolve(data) . 如果要通过错误消息拒绝请求/响应,则可以返回DioError对象或返回dio.reject(errMsg) .

dio.interceptors.add(InterceptorsWrapper(
  onRequest:(RequestOptions options) {
   return dio.resolve("fake data")
  },
));
Response response = await dio.get("/test");
print(response.data);//"fake data"

Lock/unlock the interceptors #

您可以通过调用拦截器的lock() / unlock方法来lock() / unlock . 一旦请求/响应拦截器被锁定,传入的请求/响应将在它们进入拦截器之前被添加到队列中,直到解锁该拦截器后,它们才会继续.

tokenDio = new Dio(); //Create a new instance to request the token.
tokenDio.options = dio;
dio.interceptors.add(InterceptorsWrapper(
    onRequest:(Options options) async {
        // If no token, request token firstly and lock this interceptor
        // to prevent other request enter this interceptor.
        dio.interceptors.requestLock.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.interceptors.requestLock.unlock();
        return options; //continue
    }
));

您可以通过调用clear()等待队列;

aliases #

请求拦截器被锁定时,传入的请求将暂停,这等效于我们锁定了当前的dio实例,因此,Dio为请求拦截器的lock/unlock 提供了两个别名.

dio.lock()== dio.interceptors.requestLock.lock()

dio.unlock()== dio.interceptors.requestLock.unlock()

dio.clear()== dio.interceptors.requestLock.clear()

Example #

出于安全原因,我们需要所有请求在标头中设置csrfToken,如果csrfToken不存在,则需要先请求一个csrfToken,然后执行网络请求,因为请求csrfToken的过程是异步的,所以我们需要在请求拦截器中执行此异步请求. 代码如下:

dio.interceptors.add(InterceptorsWrapper(
    onRequest: (Options options) async {
        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;
        }
    }
));

有关完整的代码,请单击此处 .

Log #

您可以将LogInterceptor设置为自动打印请求/响应日志,例如:

dio.interceptors.add(LogInterceptor(responseBody: false)); //开启请求日志

Custom Interceptor #

您可以通过扩展Interceptor类来定制拦截Interceptor . 有一个示例实现了一个简单的缓存策略: 自定义缓存拦截器 .

dio_cookie_manager软件包是Dio的cookie管理器.

Handling Errors #

发生错误时,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 scheme #

 {
  /// Response info, it may be `null` if the request can't reach to
  /// the http server, for example, occurring a dns error, network is not available.
  Response response;

  /// Error descriptions.
  String message;

  DioErrorType type;

  /// The original error/exception object; It's usually not null when `type`
  /// is DioErrorType.DEFAULT
  dynamic error;
}

DioErrorType #

enum DioErrorType {
  /// When opening  url timeout, it occurs.
  CONNECT_TIMEOUT,

  ///It occurs when receiving timeout.
  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,

  /// Default error type, Some other Error. In this case, you can
  /// read the DioError.error if it is not null.
  DEFAULT,
}

Using application/x-www-form-urlencoded format #

默认情况下,Dio将请求数据(字符串类型除外)序列化为JSON . 要改为以application/x-www-form-urlencoded格式发送数据,您可以:

//Instance level
dio.options.contentType= Headers.formUrlEncodedContentType;
//or works once
dio.post("/info", data:{"id":5}, 
         options: Options(contentType:Headers.formUrlEncodedContentType ));

Sending FormData #

您还可以使用Dio发送FormData,它将在multipart/form-data发送multipart/form-data ,并且它支持上传文件.

FormData formData = FormData.from({
    "name": "wendux",
    "age": 25,
    "file": await MultipartFile.fromFile("./text.txt",filename: "upload.txt")
});
response = await dio.post("/info", data: formData);

有一个完整的例子在这里 .

Multiple files upload #

FormData添加多个文件有两种方法,唯一的区别是数组类型的上传键不同.

  FormData.fromMap({
    "files": [
      MultipartFile.fromFileSync("./example/upload.txt",
          filename: "upload.txt"),
      MultipartFile.fromFileSync("./example/upload.txt",
          filename: "upload.txt"),
    ]
  });

上载密钥最终变为" files []",这是因为许多后端服务在获取文件数组时在密钥中添加了中间括号. 如果您不希望使用[[]" ,则应按以下方式创建FormData(不要使用FormData.fromMap ):

  var formData = FormData();
  formData.files.addAll([
    MapEntry(
      "files",
       MultipartFile.fromFileSync("./example/upload.txt",
          filename: "upload.txt"),
    ),
    MapEntry(
      "files",
      MultipartFile.fromFileSync("./example/upload.txt",
          filename: "upload.txt"),
    ),
  ]);

Transformer #

Transformer允许在将请求/响应数据发送到服务器或从服务器接收之前进行更改. 这仅适用于请求方法" PUT"," POST"和" PATCH". Dio已经实现了DefaultTransformer ,并作为默认的Transformer . 如果要自定义请求/响应数据的Transformer ,可以自行提供一个Transformer ,并通过设置dio.transformer替换DefaultTransformer .

In flutter #

如果在抖动开发中使用dio,则最好使用[compute]函数在后台解码json.


// Must be top-level function
_parseAndDecode(String response) {
  return jsonDecode(response);
}

parseJson(String text) {
  return compute(_parseAndDecode, text);
}

void main() {
  ...
  //Custom jsonDecodeCallback
  (dio.transformer as DefaultTransformer).jsonDecodeCallback = parseJson;
  runApp(MyApp());
}

Other Example #

有一个自定义Transformer的示例.

HttpClientAdapter #

HttpClientAdapter是Dio和HttpClient之间的桥梁.

Dio为开发人员实现了标准且友好的API.

HttpClient:这是发出Http请求的实际对象.

我们可以使用任何HttpClient而不只是dart:io:HttpClient来发出Http请求. 我们所需要的只是提供HttpClientAdapter . Dio的默认HttpClientAdapter是DefaultHttpClientAdapter .

dio.httpClientAdapter = new DefaultHttpClientAdapter();

是自定义适配器的一个简单示例.

Using proxy #

DefaultHttpClientAdapter提供一个回调,以将代理设置为dart:io:HttpClient ,例如:

import 'package:dio/dio.dart';
import 'package:dio/adapter.dart';
...
(dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (client) {
    // config the http client
    client.findProxy = (uri) {
        //proxy all request to localhost:8888
        return "PROXY localhost:8888";
    };
    // you can also create a new HttpClient to dio
    // return new HttpClient();
};

有一个完整的例子在这里 .

Https certificate verification #

有两种验证https证书的方法. 假设证书格式为PEM,代码如下:

String PEM="XXXXX"; // certificate content
(dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate  = (client) {
    client.badCertificateCallback=(X509Certificate cert, String host, int port){
        if(cert.pem==PEM){ // Verify the certificate
            return true;
        }
        return false;
    };
};

另一种方法是在创建HttpClient时创建SecurityContext

(dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate  = (client) {
    SecurityContext sc = new SecurityContext();
    //file is the path of certificate
    sc.setTrustedCertificates(file);
    HttpClient httpClient = new HttpClient(context: sc);
    return httpClient;
};

这样,证书的格式必须为PEM或PKCS12.

Http2 support #

dio_http2_adapter软件包是一个支持Http / 2.0的Dio HttpClientAdapter.

Cancellation #

您可以使用取消令牌取消请求. 一个令牌可以与多个请求共享. 当调用令牌的cancel方法时,所有带有此令牌的请求都将被取消.

CancelToken token = CancelToken();
dio.get(url1, cancelToken: token);
dio.get(url2, cancelToken: token);

// cancel the requests with "cancelled" message.
token.cancel("cancelled");

有一个完整的例子在这里 .

Extends Dio class #

Dio是带有工厂构造函数的抽象类,因此我们不直接扩展Dio类. 为此,我们可以扩展DioForNativeDioForBrowser ,例如:

import 'package:dio/dio.dart';
import 'package:dio/native_imp.dart'; //If in browser, import 'package:dio/browser_imp.dart'

class Http extends DioForNative {
  Http([BaseOptions options]):super(options){
    // do something
  }
}

我们也可以实现我们的Dio客户:

class MyDio with DioMixin implements Dio{
  // ...
}

这个开源项目由https://flutterchina.club授权,许可证为MIT.

Features and bugs #

请在问题跟踪器中提交功能请求和错误.

帮我买一杯咖啡(微信扫描):

3.0.9 2020.2.24 #

  • 添加测试用例

3.0.8 2019.12.29 #

  • 代码风格改进

3.0.7 2019.11.25 #

  • 合并#574:修复上传图片标题错误,同时支持oss和其他服务器

3.0.6 2019.11.22 #

  • 恢复#562,并修复#566

3.0.5 2019.11.19 #

  • 合并#557#531

3.0.4 2019.10.29 #

  • 修复#502#515#523

3.0.3 2019.10.1 #

  • 修复编码错误

3.0.2 2019.9.26 #

  • 修复#474#480

3.0.2-dev.1 2019.9.20 #

  • 修复#470#471

3.0.1 2019.9.20 #

  • 修复#467
  • Export DioForNative and DioForBrowser classes.

3.0.0 #

New features #

Change List #

  • Options.cookies

  • Options.connectionTimeout ;我们应该在BaseOptions配置连接超时. 出于保持活动的原因,并非每个请求都需要单独的连接.

  • 在Flutter Web中, Options.followRedirectsOptions.maxRedirectsResponse.redirects没有意义,因为重定向可以由浏览器自动处理.

  • FormData.from,use FormData.fromMap instead.

  • 删除 Formdata.asBytes() Formdata.asBytesAsync() ,请改用Formdata.readAsBytes() .

  • Delete UploadFileInfo class, MultipartFile instead.

  • 拦截器的回调的返回类型从FutureOr<dynamic>更改为Future . 原因就在这里 .

  • 由于HttpHeaders位于Flutter Web中不支持的" dart:io"库中,因此Response.headers的类型从HttpHeaders更改为Headers .

2.1.16 #

deleteOnError参数添加到downloadUri

2.1.14 #

  • 修复#402#385#422

2.1.13 #

  • 修复#369

2.1.12 #

  • 修复#367#365

2.1.10 #

  • 修复#360

2.1.9 #

  • 支持flutter版本> = 1.8(修复#357)

2.1.8 #

  • 修复#354#312
  • 允许带有请求正文的"删除"方法(#223)

2.1.7 #

  • 修复#321#318

2.1.6 #

2.1.5 #

2.1.4 #

  • Add options.responseDecoder
  • 通过实现Exception而不是Error使DioError可捕获

2.1.3 #

ResponseResponseBody添加statusMessage属性

2.1.2 #

2.x的第一个稳定版本

2.0 #

重构拦截器

  • 支持添加多个拦截器.
  • 添加日志拦截器
  • 添加CookieManager拦截器

API

  • 支持乌里
  • 支持所有请求API的queryParameters
  • 修改get API

Options

  • 将选项分为三类:选项,BaseOptions,RequestOptions
  • 为BaseOptions添加queryParameterscookies

Adapter

  • 抽象的HttpClientAdapter层.
  • 提供一个DefaultHttpClientAdapter,它通过dart:io:HttpClient发出http请求

0.1.8 #

  • 将文件名" TransFormer"更改为" Transformer"
  • 将" dio.transFormer"更改为" dio.transformer"
  • change deprecated "UTF8" to "utf8"

0.1.5 #

  • 为dio实例添加clear方法

0.1.4 #

  • fix download bugs

0.1.3 #

  • 支持使用Array上传文件
  • 支持在onHttpClientCreate由用户自行创建HttpClient
  • 支持通用
  • 错误修复

0.0.1 #

  • 初始版本,由Stagehand创建

example/dio.dart

import 'package:dio/dio.dart';

/// More examples see https://github.com/flutterchina/dio/tree/master/example
main() async {
  var dio = Dio();
  Response response = await dio.get('https://google.com');
  print(response.data);
}

Use this package as a library

1. Depend on it

将此添加到包的pubspec.yaml文件中:


dependencies:
  dio: ^3.0.9

2. Install it

您可以从命令行安装软件包:

与酒吧:


$ pub get

使用Flutter:


$ flutter pub get

另外,您的编辑器可能支持pub getflutter pub get . 查看您的编辑器文档以了解更多信息.

3. Import it

现在,在Dart代码中,您可以使用:


import 'package:dio/dio.dart';
  
Popularity:
描述该程序包相对于其他程序包的受欢迎程度. [更多]
99
Health:
从静态分析得出的代码运行状况. [更多]
100
Maintenance:
反映出软件包的整洁和最新状态. [更多]
100
Overall:
以上的加权分数. [更多]
100
了解有关得分的更多信息.

我们在2020年5月24日对该软件包进行了分析,并在下面提供了得分,详细信息和建议. using: 分析已完成,状态使用以下命令 :

  • 飞镖:2.8.1
  • 直到:0.13.8-dev

Health suggestions

Format lib/src/dio.dart.

运行dartfmt格式化lib/src/dio.dart .

Format lib/src/transformer.dart.

运行dartfmt格式化lib/src/transformer.dart .

Dependencies

Package Constraint Resolved Available
直接依赖
Dart SDK > 2.4.0 <3.0.0
http_parser > = 0.0.1 <4.0.0 3.1.4
path ^1.6.4 1.7.0
传递依存关系
charcode 1.1.3
collection 1.14.12
meta 1.1.8
source_span 1.7.0
string_scanner 1.0.5
term_glyph 1.1.0
typed_data 1.1.6
开发依赖
pedantic 1.1.0
test ^1.5.1

by  ICOPY.SITE