A powerful Http client for Dart, which supports Interceptors, Global configuration, FormData, Request Cancellation, File downloading, Timeout etc.
dependencies:
dio: ^4.0.6
Already know Dio 3 and just want to learn about what's new in Dio 4? Check out the Migration Guide!
import 'package:dio/dio.dart';
void getHttp() async {
try {
var response = await Dio().get('http://www.google.com');
print(response);
} catch (e) {
print(e);
}
}
🎉 A curated list of awesome things related to dio.
Plugins | Status | Description |
---|---|---|
dio_cookie_manager | A cookie manager for Dio | |
dio_http2_adapter | A Dio HttpClientAdapter which support Http/2.0 | |
dio_smart_retry | Flexible retry library for Dio | |
http_certificate_pinning | Https Certificate pinning for Flutter | |
curl_logger_dio_interceptor | A Flutter curl-command generator for Dio. | |
dio_cache_interceptor | Dio HTTP cache interceptor with multiple stores respecting HTTP directives (or not) | |
dio_http_cache | A simple cache library for Dio like Rxcache in Android | |
pretty_dio_logger | Pretty Dio logger is a Dio interceptor that logs network calls in a pretty, easy to read format. |
Welcome to submit Dio's third-party plugins and related libraries here .
Performing a GET
request:
Response response;
var dio = 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());
Performing a POST
request:
response = await dio.post('/test', data: {'id': 12, 'name': 'wendu'});
Performing multiple concurrent requests:
response = await Future.wait([dio.post('/info'), dio.get('/token')]);
Downloading a file:
response = await dio.download('https://www.google.com/', './xx.html');
Get response stream:
Response<ResponseBody> rs;
rs = await Dio().get<ResponseBody>(url,
options: Options(responseType: ResponseType.stream), // set responseType to `stream`
);
print(rs.data.stream); //response stream
Get response with bytes:
Response<List<int>> rs
rs = await Dio().get<List<int>>(url,
options: Options(responseType: ResponseType.bytes), // set responseType to `bytes`
);
print(rs.data); // List<int>
Sending FormData:
var formData = FormData.fromMap({
'name': 'wendux',
'age': 25,
});
var response = await dio.post('/info', data: formData);
Uploading multiple files to server by FormData:
var 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'),
]
});
var response = await dio.post('/info', data: formData);
Listening the uploading progress:
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');
},
);
Post binary data by Stream:
// 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
},
),
);
…you can find all examples code here.
You can create instance of Dio with an optional BaseOptions
object:
var dio = 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.
var options = BaseOptions(
baseUrl: 'https://www.xx.com/api',
connectTimeout: 5000,
receiveTimeout: 3000,
);
Dio dio = Dio(options);
The core API in Dio instance is:
Future request(String path, {data,Map queryParameters, Options options,CancelToken cancelToken, ProgressCallback onSendProgress, ProgressCallback onReceiveProgress)
response = await dio.request(
'/test',
data: {'id':12,'name':'xx'},
options: Options(method:'GET'),
);
For convenience aliases have been provided for all supported request methods.
Future<Response> get(...)
Future<Response> post(...)
Future<Response> put(...)
Future<Response> delete(...)
Future<Response> head(...)
Future<Response> put(...)
Future<Response> path(...)
Future<Response> download(...)
Future<Response> fetch(RequestOptions)
The Options class describes the http request information and configuration. Each Dio instance has a base config for all requests maked by itself, and we can override the base config with [Options] when make a single request. The [BaseOptions] declaration as follows:
{
/// 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;
/// [collectionFormat] indicates the format of collection data in request
/// options which defined in [CollectionFormat] are `csv`, `ssv`, `tsv`, `pipes`, `multi`,`multiCompatible`.
/// The default value is `multiCompatible`
late CollectionFormat collectionFormat;
}
There is a complete example here.
The response for a request contains the following information.
{
/// 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;
String? statusMessage;
/// 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;
}
When request is succeed, you will receive the response as follows:
Response response = await dio.get('https://www.google.com');
print(response.data);
print(response.headers);
print(response.requestOptions);
print(response.statusCode);
For each dio instance, We can add one or more interceptors, by which we can intercept requests 、 responses and errors before they are handled by then
or catchError
.
dio.interceptors.add(InterceptorsWrapper(
onRequest:(options, handler){
// Do something before request is sent
return handler.next(options); //continue
// If you want to resolve the request with some custom data,
// you can resolve a `Response` object eg: `handler.resolve(response)`.
// If you want to reject the request with a error message,
// you can reject a `DioError` object eg: `handler.reject(dioError)`
},
onResponse:(response,handler) {
// Do something with response data
return handler.next(response); // continue
// If you want to reject the request with a error message,
// you can reject a `DioError` object eg: `handler.reject(dioError)`
},
onError: (DioError e, handler) {
// Do something with response error
return handler.next(e);//continue
// If you want to resolve the request with some custom data,
// you can resolve a `Response` object eg: `handler.resolve(response)`.
}
));
Simple interceptor example:
import 'package:dio/dio.dart';
class CustomInterceptors extends Interceptor {
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
print('REQUEST[${options.method}] => PATH: ${options.path}');
return super.onRequest(options, handler);
}
@override
void onResponse(Response response, ResponseInterceptorHandler handler) {
print('RESPONSE[${response.statusCode}] => PATH: ${response.requestOptions.path}');
super.onResponse(response, handler);
}
@override
Future onError(DioError err, ErrorInterceptorHandler handler) {
print('ERROR[${err.response?.statusCode}] => PATH: ${err.requestOptions.path}');
return super.onError(err, handler);
}
}
In all interceptors, you can interfere with their execution flow. If you want to resolve the request/response with some custom data,you can call handler.resolve(Response)
. If you want to reject the request/response with a error message, you can call handler.reject(dioError)
.
dio.interceptors.add(InterceptorsWrapper(
onRequest:(options, handler) {
return handler.resolve(Response(requestOptions:options,data:'fake data'));
},
));
Response response = await dio.get('/test');
print(response.data);//'fake data'