Dio is a Dart Http library that supports Restful apis, FormData, interceptors, request cancellation, Cookie management, file upload/download, timeout, etc.

The document language: English | Chinese simplified

dio

Dart Http request library with support for Restful apis, FormData, interceptors, request cancellation, Cookie management, file upload/download, timeouts…

Add the dependent

dependencies:
  dio: ^x.x.x  // latest version
Copy the code

A minimalist example

import 'package:dio/dio.dart';
Dio dio = new Dio();
Response response=await dio.get("https://www.google.com/");
print(response.data);
Copy the code

The content list

  • The sample

  • Dio APIs

  • Request configuration

  • The response data

  • The interceptor

  • Error handling

  • Use Application/X-www-form-urlencoded

  • FormData

  • converter

  • Setting the Http Proxy

  • The request to cancel

  • Cookie management

  • Features and bugs

The sample

Make a GET request:

Response response;
response=await dio.get("/test? id=12&name=wendu")
print(response.data.toString());
// Request parameters can also be passed through objects.
response=await dio.get("/test",data:{"id":12."name":"wendu"})
print(response.data.toString());
Copy the code

Make a POST request:

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

Initiate multiple concurrent requests:

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

Download file:

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

Send the FormData:

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

Upload multiple files via 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")}); response =await dio.post("/info", data: formData)
Copy the code

… You can get all the sample code here.

Dio APIs

Create a Dio instance and configure it

You can create a Dio instance using the default configuration or passing an optional Options argument:

Dio dio = new Dio; // Use the default Settings

// Configure the dio instance
dio.options.baseUrl="https://www.xx.com/api" 
dio.options.connectTimeout = 5000; //5s
dio.options.receiveTimeout=3000;  

// Or create dio instance by passing an 'options'
Options options= new Options(
    baseUrl:"https://www.xx.com/api",
    connectTimeout:5000,
    receiveTimeout:3000
);
Dio dio = new Dio(options);
Copy the code

The core API for Dio instances is:

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

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

Request method alias

For ease of use, Dio provides several other Restful apis that are aliases for 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})

Request configuration

Below are all the request configuration options. If method is not specified, the default is GET:

{
  /// Http method.
  String method;

  / / / request base address, can contain subpaths, such as: "https://www.google.com/api/".
  String baseUrl;

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

  /// Timeout time for connecting to the server, in milliseconds.
  int connectTimeout;

  /// The interval in milliseconds between two data receives on the response stream. If the interval exceeds [receiveTimeout],
  /// [Dio] will throw a [dioErrorType. RECEIVE_TIMEOUT] exception.
  /// Note: this is not the total time to receive data.
  int receiveTimeout;

  /// Request data, which can be any type.
  var data;

  /// request the path if`path`Start with "HTTP (s)", then`baseURL`Will be ignored; Otherwise,
  /// will concatenate the full URL with baseUrl.
  String path="";

  /// The content-type of the request. The default value is [contentType.json].
  // If you want to "application/x-www-form-urlencoded" format,
  /// This option can be set to`ContentType.parse("application/x-www-form-urlencoded")`So that (Dio)
  /// the request body is automatically encoded.
  ContentType contentType;

  /// [responseType] indicates the format in which the response data is expected to be received.
  [ResponseType] currently accepts three types of ResponseType`JSON`.`STREAM`.`PLAIN`.
  ///
  /// The default value is`JSON`When the content-Type in the response header is "Application/JSON", DIO automatically converts the response content into a JSON object.
  /// If you want to receive the response data in binary mode, such as downloading a binary file, you can use it`STREAM`.
  ///
  /// If you want to receive response data in text (string) format, use the`PLAIN`.
  ResponseType responseType;

  /// User-defined field, available in [Interceptor], [TransFormer], and [Response].
  Map<String.dynamic> extra;
}
Copy the code

Here is an example of completion.

The response data

When the request succeeds, a Response object is returned containing the following fields:

{
  /// Response data, which may have been converted, refer to [ResponseType] in Options for details.
  var data;
  / / / response headers
  HttpHeaders headers;
  /// This time request information
  Options request;
  /// Http status code.
  int statusCode;
  /// a custom field of the response object (which can be set in the interceptor) that the caller can use in the`then`In the acquisition.
  Map<String.dynamic> extra;
}
Copy the code

The following is an example:

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

The interceptor

Each Dio instance has a RequestInterceptor and a ResponseInterceptor, With interceptors you can do some uniform preprocessing before or after a request (but not yet processed by then or catchError).

 dio.interceptor.request.onSend = (Options options){
     Do something before the request is sent
     return options; //continue
     // If you want to complete the request and return some custom data, either return a 'Response' object or return 'dio.resolve(data)'.
     // The request will be terminated, the upper then will be called, and the data returned in the THEN will be your custom data.
     //
     // If you want to terminate the request and trigger an error, you can return a 'DioError' object, or 'dio.reject(errMsg)',
     // The request will be aborted and an exception will be raised and the upper catchError will be called.
 }
 dio.interceptor.response.onSuccess = (Response response) {
     // Do some preprocessing before returning response data
     return response; // continue
 };
 dio.interceptor.response.onError = (DioError e){
     // Do some preprocessing when the request fails
     return DioError;//continue
 }    
Copy the code

If you want to remove interceptors, you can set them to NULL:

dio.interceptor.request.onSend=null;
dio.interceptor.response.onSuccess=null;
dio.interceptor.response.onError=null;
Copy the code

Complete and terminate the request/response

In all interceptors, you can change the request execution flow. If you want to complete the request/Response and return custom data, you can either return a Response object or return the result dio.resolve(data). If you want to abort a request/response (triggering an error, the upper catchError is called), then either return a DioError object or return dio.reject(errMsg) as a result.

 dio.interceptor.request.onSend = (Options options){
     return dio.resolve("fake data")    
 }
 Response response= await dio.get("/test");
 print(response.data);//"fake data"
Copy the code

Asynchronous tasks are supported in interceptors

Interceptors support both synchronous and asynchronous tasks. Here is an example of an asynchronous task initiated in a request interceptor:

  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   
 }
Copy the code

The Lock/unlock the interceptor

You can lock /unlock an interceptor by calling its lock()/unlock methods. Once the request/response interceptor is locked, subsequent requests/responses are queued before entering the request/response interceptor until unlocked. This is useful in some scenarios that require serialization of requests/responses, as we’ll show you in an example below.

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   
 }
Copy the code

The alias

When the request interceptor is locked, subsequent requests are paused, which is equivalent to locking the DIO instance, so the DIO example provides an alias method for the request interceptor lock/ UNLOCK:

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

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

The sample

Consider a scenario where, for security reasons, we need to add a csrfToken to all request headers. If the csrfToken does not exist, we request the csrfToken first. After obtaining the csrfToken, we make subsequent requests. Since the process of requesting a csrfToken is asynchronous, we need to lock subsequent requests during the request (because they require a csrfToken) until the csrfToken request is successful, and then unlock it, with the following code:

dio.interceptor.request.onSend = (Options options) {
    print('the send request: the 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;
      returnoptions; }};Copy the code

The full sample code can be found here.

Error handling

Dio wraps Error/Exception as a DioError when an Error occurs during a request:

  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)
      }  
  }
Copy the code

DioError field

 {
  /// Response information, if the error occurred before the server returned data, is`null`
  Response response;

  /// Error description.
  String message;
  
  /// Error type, see below
  DioErrorType type;

  /// Error stack information, possibly null
  StackTrace stackTrace;
}
Copy the code

DioErrorType

enum DioErrorType {
  /// Default error type, usually occurs before connecting the server.
  DEFAULT,

  /// When opening url timeout, it occurs.
  CONNECT_TIMEOUT,

  /// Whenevermore than [receiveTimeout] (in milliseconds) passes between two events from response stream,
  /// [Dio]will throw the [DioError] with [DioErrorType.RECEIVE_TIMEOUT].
  ///
  /// Note: This is notthe 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
}
Copy the code

Use Application/X-www-form-urlencoded

By default, Dio serializes request data (except String) to JSON. If you want to encode in Application/X-www-form-urlencoded format, you can explicitly set 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")))    
Copy the code

Here’s an example.

FormData

Dio supports sending FormData. The requested data will be encoded in multipart/form-data format. FormData can contain one or more files.

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)
Copy the code

Note: Only the POST method supports sending FormData.

Here’s a complete example.

converter

TransFormer is used to encode and decode request and response data. Dio implements a DefaultTransformer DefaultTransformer as the DefaultTransformer. If you want custom codecs for request/response data, you can provide custom converters with dio.transformer Settings.

Request the converter TransFormer. TransformRequest (…). Will only be used for the ‘PUT’, ‘POST’, and ‘PATCH’ methods because only these can carry the request body. But the response of converter TransFormer. TransformResponse () method will be used for all requests return data.

Execution flow

Although in the interceptor can also for data preprocessing, but converter main duty is to request/response data decoding, separate the converter separately, one is for the sake of and interceptors decoupling, 2 it is to do not change the original request data (if you modify the request data in the interceptor (options. The data), overwrite the original request data, At some point you may need raw request data). Dio’s request flow is:

Request Interceptor >> Request Converter >> Initiate request >> Response Converter >> Response Interceptor >> End Result.

This is an example of a custom converter.

Setting the Http Proxy

Dio is an HTTP request made using HttpClient, so you can configure HttpClient to support proxies as shown in the following example:

  dio.onHttpClientCreate = (HttpClient client) {
    client.findProxy = (uri) {
      //proxy all request to localhost:8888
      return "PROXY localhost:8888";
    };
  };
Copy the code

See here for a complete example.

The request to cancel

You can cancel a initiated request by using the 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");
Copy the code

Note: The same Cancel token can be used for multiple requests. When a Cancel token is cancelled, all requests using that Cancel token are cancelled.

See Cancel example for a complete example.

Cookie management

You can automatically manage request/response cookies with the cookieJar.

The Dio Cookie management API is based on the open source library Cookie_JAR.

You can create a CookieJar or PersistCookieJar to help you automatically manage cookies. Dio uses the CookieJar by default and it keeps cookies in memory. If you want to persist cookies, use PersistCookieJar as shown in the following code:

var dio = new Dio();
dio.cookieJar=new PersistCookieJar("./cookies");
Copy the code

The PersistCookieJar implements the standard cookie policy in the RFC. The PersistCookieJar stores cookies in a file, so cookies persist until they are explicitly deleted with the delete call.

For more information about the cookie_JAR: github.com/flutterchin… .

Copyright & License

This open source project is licensed by Flutter Chinese (FlutterChina. club). The license is MIT. If you like, welcome star.

Flutter Chinese open source project plans

Develop a series of common (practical) packages and plug-ins in addition to the Flutter SDK to enrich the third-party Flutter library and contribute to the Flutter ecology from Chinese developers. All projects will be published on Github Flutter Chinese Organization. All source contributors will join our Organization as members. At present, several open source projects have started public beta in the community. You are welcome to join the development or testing. For details, please check out Flutter Chinese Open Source Project. If you would like to participate in the Open Source Project program, please send an email to [email protected] with a self-introduction (personal basic information + technical expertise/interest).

Features and bugs

Please file feature requests and bugs at the issue tracker.