dio
v5.11.1A powerful HTTP networking package, supports Interceptors, Aborting and canceling a request, Custom adapters, Transformers, etc.
Архив пакета: https://pubdev.letsnova.ru/api/archives/dio/5.11.1.tar.gz
dart pub add dioREADME
dio
Language: English | 简体中文
A powerful HTTP networking package for Dart/Flutter, supports Global configuration, Interceptors, FormData, Request cancellation, File uploading/downloading, Timeout, Custom adapters, Transformers, etc.
Don't forget to add #dio topic to your published dio related packages! See more: https://dart.dev/tools/pub/pubspec#topics
Table of content
- dio
- Get started
- Awesome dio
- Examples
- Performing a
GETrequest - Performing a
POSTrequest - Performing a
QUERYrequest - Performing multiple concurrent requests
- Downloading a file
- Get response stream
- Get response with bytes
- Sending a
FormData - Uploading multiple files to server by FormData
- Listening the uploading progress
- Post binary data with Stream
- Performing a
- Dio APIs
- Handling Errors
- Using application/x-www-form-urlencoded format
- Sending FormData
- Transformer
- HttpClientAdapter
- HTTP/2 support
- Cancellation
- Extends Dio class
- Cross-Origin Resource Sharing on Web (CORS)
Get started
Install
Add the dio package to your
pubspec dependencies.
Before you upgrade: Breaking changes might happen in major and minor versions of packages.
See the Migration Guide for the complete breaking changes list.
Super simple to use
import 'package:dio/dio.dart';
final dio = Dio();
void getHttp() async {
final response = await dio.get('https://dart.dev');
print(response);
}
Awesome dio
🎉 A curated list of awesome things related to dio.
Plugins
Welcome to submit third-party plugins and related libraries in here.
Examples
Performing a GET request
import 'package:dio/dio.dart';
final dio = Dio();
void request() async {
Response response;
response = await dio.get('/test?id=12&name=dio');
print(response.data.toString());
// The below request is the same as above.
response = await dio.get(
'/test',
queryParameters: {'id': 12, 'name': 'dio'},
);
print(response.data.toString());
}
Performing a POST request
response = await dio.post('/test', data: {'id': 12, 'name': 'dio'});
Performing a QUERY request
The QUERY method (RFC 10008) is safe and idempotent like GET, but allows a
request body, which is useful for complex queries that do not fit in the URL.
response = await dio.query('/search', data: {'filter': {'name': 'dio'}});
Performing multiple concurrent requests
List<Response> responses = await Future.wait([dio.post('/info'), dio.get('/token')]);
Downloading a file
response = await dio.download(
'https://pub.dev/',
(await getTemporaryDirectory()).path + 'pub.html',
);
On Web, the second argument is used as the browser's suggested filename instead
of a local filesystem path. The browser chooses the actual saved location, the
response is loaded into memory before the download is triggered, and CORS still
applies. FileAccessMode.append is not supported, deleteOnError has no local
file to delete, and custom lengthHeader values are not used for Web progress
totals.
Get response stream
final rs = await dio.get(
url,
options: Options(responseType: ResponseType.stream), // Set the response type to `stream`.
);
print(rs.data.stream); // Response stream.
Get response with bytes
final rs = await Dio().get<List<int>>(
url,
options: Options(responseType: ResponseType.bytes), // Set the response type to `bytes`.
);
print(rs.data); // Type: List<int>.
Sending a FormData
final formData = FormData.fromMap({
'name': 'dio',
'date': DateTime.now().toIso8601String(),
});
final response = await dio.post('/info', data: formData);
Uploading multiple files to server by FormData
final formData = FormData.fromMap({
'name': 'dio',
'date': DateTime.now().toIso8601String(),
'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'),
]
});
final response = await dio.post('/info', data: formData);
Listening the uploading progress
final response = await dio.post(
'https://www.dtworkroom.com/doris/1/2.0.0/test',
data: {'aa': 'bb' * 22},
onSendProgress: (int sent, int total) {
print('$sent $total');
},
);
Post binary data with Stream
// Binary data
final postData = <int>[0, 1, 2];
await dio.post(
url,
data: Stream.fromIterable(postData.map((e) => [e])), // Creates a Stream<List<int>>.
options: Options(
headers: {
Headers.contentLengthHeader: postData.length, // Set the content-length.
},
),
);
Note: content-length must be set if you want to subscribe to the sending progress.
See all examples code here.
Dio APIs
Creating an instance and set default configs
It is recommended to use a singleton of
Dioin projects, which can manage configurations like headers, base urls, and timeouts consistently. Here is an example that use a singleton in Flutter.
You can create instance of Dio with an optional BaseOptions object:
final dio = Dio(); // With default `Options`.
void configureDio() {
// Set default configs
dio.options.baseUrl = 'https://api.pub.dev';
dio.options.connectTimeout = Duration(seconds: 5);
dio.options.receiveTimeout = Duration(seconds: 3);
// Or create `Dio` with a `BaseOptions` instance.
final options = BaseOptions(
baseUrl: 'https://api.pub.dev',
connectTimeout: Duration(seconds: 5),
receiveTimeout: Duration(seconds: 3),
);
final anotherDio = Dio(options);
// Or clone the existing `Dio` instance with all fields.
final clonedDio = dio.clone();
}
The core API in Dio instance is:
Future<Response<T>> request<T>(
String path, {
Object? data,
Map<String, dynamic>? queryParameters,
CancelToken? cancelToken,
Options? options,
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
});
final response = await dio.request(
'/test',
data: {'id': 12, 'name': 'dio'},
options: Options(method: 'GET'),
);
Request Options
There are two request options concepts in the Dio library:
BaseOptions and Options.
The BaseOptions include a set of base settings for each Dio(),
and the Options describes the configuration for a single request.
These options will be merged when making requests.
The Options declaration is as follows:
/// The HTTP request method.
String method;
/// Timeout when sending data.
///
/// Throws the [DioException] with
/// [DioExceptionType.sendTimeout] type when timed out.
///
/// `null` or `Duration.zero` means no timeout limit.
Duration? sendTimeout;
/// Timeout when receiving data.
///
/// The timeout represents:
/// - a timeout before the connection is established
/// and the first received response bytes.
/// - the duration during data transfer of each byte event,
/// rather than the total duration of the receiving.
///
/// Throws the [DioException] with
/// [DioExceptionType.receiveTimeout] type when timed out.
///
/// `null` or `Duration.zero` means no timeout limit.
Duration? receiveTimeout;
/// Timeout when transforming response data.
///
/// Throws the [DioException] with
/// [DioExceptionType.transformTimeout] type when timed out.
/// On web, timeout handling is best-effort because synchronous JavaScript
/// work cannot be preempted.
///
/// `null` or `Duration.zero` means no timeout limit.
Duration? transformTimeout;
/// Custom field that you can retrieve it later in [Interceptor],
/// [Transformer] and the [Response.requestOptions] object.
Map<String, dynamic>? extra;
/// HTTP request headers.
///
/// The keys of the header are case-insensitive,
/// e.g.: `content-type` and `Content-Type` will be treated as the same key.
Map<String, dynamic>? headers;
/// Whether the case of header keys should be preserved.
///
/// Defaults to false.
///
/// This option WILL NOT take effect on these circumstances:
/// - XHR ([HttpRequest]) does not support handling this explicitly.
/// - The HTTP/2 standard only supports lowercase header keys.
bool? preserveHeaderCase;
/// The type of data that [Dio] handles with options.
///
/// The default value is [ResponseType.json].
/// [Dio] will parse response string to JSON object automatically
/// when the content-type of response is [Headers.jsonContentType].
///
/// See also:
/// - `plain` if you want to receive the data as `String`.
/// - `bytes` if you want to receive the data as the complete bytes.
/// - `stream` if you want to receive the data as streamed binary bytes.
ResponseType? responseType;
/// The request content-type.
///
/// The default `content-type` for requests will be implied by the
/// [ImplyContentTypeInterceptor] according to the type of the request payload.
/// The interceptor can be removed by
/// [Interceptors.removeImplyContentTypeInterceptor].
String? contentType;
/// Defines whether the request is considered to be successful
/// with the given status code.
/// The request will be treated as succeed if the callback returns true.
ValidateStatus? validateStatus;
/// Whether to retrieve the data if status code indicates a failed request.
///
/// Defaults to true.
bool? receiveDataWhenStatusError;
/// See [HttpClientRequest.followRedirects].
///
/// Defaults to true.
bool? followRedirects;
/// The maximum number of redirects when [followRedirects] is `true`.
/// [RedirectException] will be thrown if redirects exceeded the limit.
///
/// Defaults to 5.
int? maxRedirects;
/// See [HttpClientRequest.persistentConnection].
///
/// Defaults to true.
bool? persistentConnection;
/// The default request encoder is [Utf8Encoder], you can set custom
/// encoder by this option.
RequestEncoder? requestEncoder;
/// The default response decoder is [Utf8Decoder], you can set custom
/// decoder by this option, it will be used in [Transformer].
ResponseDecoder? responseDecoder;
/// Indicates the format of collection data in request query parameters and
/// `x-www-url-encoded` body data.
///
/// Defaults to [ListFormat.multi].
ListFormat? listFormat;
There is a complete example here.
Response
The response for a request contains the following information.
/// Response body. may have been transformed, please refer to [ResponseType].
T? data;
/// The corresponding request info.
RequestOptions requestOptions;
/// HTTP status code.
int? statusCode;
/// Returns the reason phrase associated with the status code.
/// The reason phrase must be set before the body is written
/// to. Setting the reason phrase after writing to the body.
String? statusMessage;
/// Whether this response is a redirect.
/// ** Attention **: Whether this field is available depends on whether the
/// implementation of the adapter supports it or not.
bool isRedirect;
/// The series of redirects this connection has been through. The list will be
/// empty if no redirects were followed. [redirects] will be updated both
/// in the case of an automatic and a manual redirect.
///
/// ** Attention **: Whether this field is available depends on whether the
/// implementation of the adapter supports it or not.
List<RedirectRecord> redirects;
/// Custom fields that only for the [Response].
Map<String, dynamic> extra;
/// Response headers.
Headers headers;
When request is succeed, you will receive the response as follows:
final response = await dio.get('https://pub.dev');
print(response.data);
print(response.headers);
print(response.requestOptions);
print(response.statusCode);
Be aware, the Response.extra is different from RequestOptions.extra,
they are not related to each other.
Interceptors
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: (RequestOptions options, RequestInterceptorHandler handler) {
// Do something before request is sent.
// If you want to resolve the request with custom data,
// you can resolve a `Response` using `handler.resolve(response)`.
// If you want to reject the request with a error message,
// you can reject with a `DioException` using `handler.reject(dioError)`.
return handler.next(options);
},
onResponse: (Response response, ResponseInterceptorHandler handler) {
// Do something with response data.
// If you want to reject the request with a error message,
// you can reject a `DioException` object using `handler.reject(dioError)`.
return handler.next(response);
},
onError: (DioException error, ErrorInterceptorHandler handler) {
// Do something with response error.
// If you want to resolve the request with some custom data,
// you can resolve a `Response` object using `handler.resolve(response)`.
return handler.next(error);
},
),
);
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}');
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(DioException err, ErrorInterceptorHandler handler) async {
print('ERROR[${err.response?.statusCode}] => PATH: ${err.requestOptions.path}');
super.onError(err, handler);
}
}
Resolve and reject the request
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'),
);
},
),
);
final response = await dio.get('/test');
print(response.data); // 'fake data'
QueuedInterceptor
Interceptor can be executed concurrently, that is,
all the requests enter the interceptor at once, rather than executing sequentially.
However, in some cases we expect that requests enter the interceptor sequentially like #590.
Therefore, we need to provide a mechanism for sequential access (step by step)
to interceptors and QueuedInterceptor can solve this problem.
Example
Because of security reasons, we need all the requests to set up
a csrfToken in the header, if csrfToken does not exist,
we need to request a csrfToken first, and then perform the network request,
because the request csrfToken progress is asynchronous,
so we need to execute this async request in request interceptor.
For the complete code see here.
LogInterceptor
You can apply the LogInterceptor to log requests and responses automatically.
Note: LogInterceptor should always be the last interceptor added,
otherwise modifications by following interceptors will not be logged.
Dart
dio.interceptors.add(LogInterceptor(responseBody: false)); // Do not output responses body.
Note: When using the default logPrint function, logs will only be printed
in DEBUG mode (when the assertion is enabled).
Alternatively dart:developer's log can also be used to log messages (available in Flutter too).
Flutter
When using Flutter, Flutters own debugPrint function should be used.
This ensures, that debug messages are also available via flutter logs.
Note: debugPrint does not mean print logs under the DEBUG mode,
it's a throttled function which helps to print full logs without truncation.
Do not use it under any production environment unless you're intended to.
dio.interceptors.add(
LogInterceptor(
logPrint: (o) => debugPrint(o.toString()),
),
);
Custom Interceptor
You can customize interceptor by extending the Interceptor/QueuedInterceptor class.
There is an example that implementing a simple cache policy:
custom cache interceptor.
Handling Errors
When an error occurs, Dio will wrap the Error/Exception to a DioException:
try {
// 404
await dio.get('https://api.pub.dev/not-exist');
} on DioException 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 != null) {
print(e.response.data)
print(e.response.headers)
print(e.response.requestOptions)
} else {
// Something happened in setting up or sending the request that triggered an Error
print(e.requestOptions)
print(e.message)
}
}
DioException
/// The request info for the request that throws exception.
RequestOptions requestOptions;
/// 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;
/// The type of the current [DioException].
DioExceptionType type;
/// The original error/exception object;
/// It's usually not null when `type` is [DioExceptionType.unknown].
Object? error;
/// The stacktrace of the original error/exception object;
/// It's usually not null when `type` is [DioExceptionType.unknown].
StackTrace? stackTrace;
/// The error message that throws a [DioException].
String? message;
DioExceptionType
See the source code.
Using application/x-www-form-urlencoded format
By default, Dio serializes request data (except String type) to JSON.
To send data in the application/x-www-form-urlencoded format instead:
// Instance level
dio.options.contentType = Headers.formUrlEncodedContentType;
// or only works once
dio.post(
'/info',
data: {'id': 5},
options: Options(contentType: Headers.formUrlEncodedContentType),
);
Sending FormData
You can also send FormData with Dio, which will send data in the multipart/form-data,
and it supports uploading files.
final formData = FormData.fromMap({
'name': 'dio',
'date': DateTime.now().toIso8601String(),
'file': await MultipartFile.fromFile('./text.txt', filename: 'upload.txt'),
});
final response = await dio.post('/info', data: formData);
You can also specify your desired boundary name which will be used
to construct boundaries of every FormData with additional prefix and suffix.
final formDataWithBoundaryName = FormData(
boundaryName: 'my-boundary-name',
);
FormDatais supported with the POST method typically.
There is a complete example here.
Multiple files upload
There are two ways to add multiple files to FormData,
the only difference is that upload keys are different for array types。
final formData = FormData.fromMap({
'files': [
MultipartFile.fromFileSync('path/to/upload1.txt', filename: 'upload1.txt'),
MultipartFile.fromFileSync('path/to/upload2.txt', filename: 'upload2.txt'),
],
});
The upload key eventually becomes files[].
This is because many back-end services add a middle bracket to key
when they get an array of files.
If you don't want a list literal,
you should create FormData as follows (Don't use FormData.fromMap):
final 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'),
),
]);
Reuse FormDatas and MultipartFiles
You should make a new FormData or MultipartFile every time in repeated requests.
A typical wrong behavior is setting the FormData as a variable and using it in every request.
It can be easy for the Cannot finalize exceptions to occur.
To avoid that, write your requests like the below code:
Future<void> _repeatedlyRequest() async {
Future<FormData> createFormData() async {
return FormData.fromMap({
'name': 'dio',
'date': DateTime.now().toIso8601String(),
'file': await MultipartFile.fromFile('./text.txt',filename: 'upload.txt'),
});
}
await dio.post('some-url', data: await createFormData());
}
Transformer
Transformer allows changes to the request/response data
before it is sent/received to/from the server.
Dio has already implemented a BackgroundTransformer as default,
which calls jsonDecode in an isolate if the response is larger than 50 KB.
If you want to customize the transformation of request/response data,
you can provide a Transformer by your self,
and replace the BackgroundTransformer by setting the dio.transformer.
Transformer.transformRequestonly takes effect when request withPUT/POST/PATCH, they're methods that can contain the request body.Transformer.transformResponsehowever, can be applied to all types of responses.
Transformer example
There is an example for customizing Transformer.
HttpClientAdapter
HttpClientAdapter is a bridge between Dio and HttpClient.
Dio implements standard and friendly APIs for developer.
HttpClient is the real object that makes Http requests.
We can use any HttpClient not just dart:io:HttpClient to make HTTP requests.
And all we need is providing a HttpClientAdapter.
The default HttpClientAdapter for Dio is IOHttpClientAdapter on native platforms,
and BrowserHttpClientAdapter on the Web platform.
They can be initiated by calling the HttpClientAdapter().
dio.httpClientAdapter = HttpClientAdapter();
If you want to use platform adapters explicitly:
- For the Web platform:
import 'package:dio/browser.dart'; // ... dio.httpClientAdapter = BrowserHttpClientAdapter(); - For native platforms:
import 'package:dio/io.dart'; // ... dio.httpClientAdapter = IOHttpClientAdapter();
Here is a simple example to custom adapter.
Using proxy
IOHttpClientAdapter provide a callback to set proxy to dart:io:HttpClient,
for example:
import 'package:dio/io.dart';
void initAdapter() {
dio.httpClientAdapter = IOHttpClientAdapter(
createHttpClient: () {
final client = HttpClient();
// Config the client.
client.findProxy = (uri) {
// Forward all request to proxy "localhost:8888".
// Be aware, the proxy should went through you running device,
// not the host platform.
return 'PROXY localhost:8888';
};
// You can also create a new HttpClient for Dio instead of returning,
// but a client must being returned here.
return client;
},
);
}
There is a complete example here.
Web does not support to set proxy.
HTTPS certificate verification
HTTPS certificate verification (or public key pinning) refers to the process of ensuring that the certificates protecting the TLS connection to the server are the ones you expect them to be. The intention is to reduce the chance of a man-in-the-middle attack. The theory is covered by OWASP.
Server Response Certificate
Unlike other methods, this one works with the certificate of the server itself.
void initAdapter() {
const String fingerprint = 'ee5ce1dfa7a53657c545c62b65802e4272878dabd65c0aadcf85783ebb0b4d5c';
dio.httpClientAdapter = IOHttpClientAdapter(
createHttpClient: () {
// Don't trust any certificate just because their root cert is trusted.
final HttpClient client = HttpClient(context: SecurityContext(withTrustedRoots: false));
// You can test the intermediate / root cert here. We just ignore it.
client.badCertificateCallback = (cert, host, port) => true;
return client;
},
validateCertificate: (cert, host, port) {
// Check that the cert fingerprint matches the one we expect.
// We definitely require _some_ certificate.
if (cert == null) {
return false;
}
// Validate it any way you want. Here we only check that
// the fingerprint matches the OpenSSL SHA256.
return fingerprint == sha256.convert(cert.der).toString();
},
);
}
You can use openssl to read the SHA256 value of a certificate:
openssl s_client -servername pinning-test.badssl.com -connect pinning-test.badssl.com:443 < /dev/null 2>/dev/null \
| openssl x509 -noout -fingerprint -sha256
# SHA256 Fingerprint=EE:5C:E1:DF:A7:A5:36:57:C5:45:C6:2B:65:80:2E:42:72:87:8D:AB:D6:5C:0A:AD:CF:85:78:3E:BB:0B:4D:5C
# (remove the formatting, keep only lower case hex characters to match the `sha256` above)
Certificate Authority Verification
These methods work well when your server has a self-signed certificate, but they don't work for certificates issued by a 3rd party like AWS or Let's Encrypt.
There are two ways to verify the root of the https certificate chain provided by the server. Suppose the certificate format is PEM, the code like:
void initAdapter() {
String PEM = 'XXXXX'; // root certificate content
dio.httpClientAdapter = IOHttpClientAdapter(
createHttpClient: () {
final client = HttpClient();
client.badCertificateCallback = (X509Certificate cert, String host, int port) {
return cert.pem == PEM; // Verify the certificate.
};
return client;
},
);
}
Another way is creating a SecurityContext when create the HttpClient:
void initAdapter() {
String PEM = 'XXXXX'; // root certificate content
dio.httpClientAdapter = IOHttpClientAdapter(
onHttpClientCreate: (_) {
final SecurityContext sc = SecurityContext();
sc.setTrustedCertificates(File(pathToTheCertificate));
final HttpClient client = HttpClient(context: sc);
return client;
},
);
}
In this way, the format of setTrustedCertificates() must be PEM or PKCS12.
PKCS12 requires password to use, which will expose the password in the code,
so it's not recommended to use in common cases.
HTTP/2 support
dio_http2_adapter is a Dio HttpClientAdapter
which supports HTTP/2.
Cancellation
You can cancel a request using a CancelToken.
One token can be shared with multiple requests.
When a token's cancel() is invoked, all requests with this token will be cancelled.
final cancelToken = CancelToken();
dio.get(url, cancelToken: cancelToken).catchError((DioException error) {
if (CancelToken.isCancel(error)) {
print('Request canceled: ${error.message}');
} else {
// handle error.
}
});
// Cancel the requests with "cancelled" message.
token.cancel('cancelled');
There is a complete example here.
Extends Dio class
Dio is an abstract class with factory constructor,
so we don't extend Dio class direct.
We can extend DioForNative or DioForBrowser instead, for example:
import 'package:dio/dio.dart';
import 'package:dio/io.dart';
// If in browser, import 'package:dio/browser.dart'.
class Http extends DioForNative {
Http([BaseOptions options]) : super(options) {
// do something
}
}
We can also implement a custom Dio client:
class MyDio with DioMixin implements Dio {
// ...
}
Cross-Origin Resource Sharing on Web (CORS)
If a request is not a simple request, the Web browser will send a CORS preflight request that checks to see if the CORS protocol is understood and a server is aware using specific methods and headers.
You can modify your requests to match the definition of simple request, or add a CORS middleware for your service to handle CORS requests.
История изменений
CHANGELOG
Before you upgrade: Breaking changes might happen in major and minor versions of packages.
See the Migration Guide for the complete breaking changes list.
Unreleased
None.
5.11.1
- Fix response stream not propagating backpressure to the underlying socket. When a consumer paused the stream, the source subscription was never paused, so the network kept buffering response data into memory, risking OOM on constrained platforms.
- Make the
badCertificateCallbackpinning test deterministic by pinning a fingerprint that cannot match the served certificate, instead of relying on badssl.com hosts serving different certificates. - Fix
NoSuchMethodErrorwhen using a class thatimplements Interceptorinstead ofextends Interceptor. The interceptor pipeline was calling private dispatch methods that only exist onInterceptorsubclasses, breaking any class using interface implementation.
5.11.0
- Add
queryandqueryUriconvenience methods for the HTTP QUERY method defined in RFC 10008, which allows a request body for safe, idempotent queries. - Fix
FusedTransformer(the default transformer) throwing aFormatExceptionon an empty response body when a customresponseDecoderis set. It now returns an empty result, consistent withSyncTransformerandBackgroundTransformer. - Fix concurrent requests hanging or reporting uncaught errors when an interceptor shares a failing Future, such as in request deduplication.
5.10.0
- Fix
FormData.readAsBytesexcessive memory usage with large payloads by replacing the O(n²)reduce+spread approach with a pre-allocatedUint8List. - Fix request hanging indefinitely when async interceptor callbacks throw without calling the handler.
- Fix
HttpException: Connection closed before full header was receivedbeing reported asDioExceptionType.unknown. - Add
transformTimeoutto bound long-running response transformations, including background JSON decoding. On web, timeout handling is best-effort because synchronous JavaScript work cannot be preempted. - Fix
FormData.clone()droppingboundaryNameandcamelCaseContentDisposition, so a retried multipart request now keeps the original options instead of silently falling back to the defaults. - Fix
QueuedInterceptorstalling its queue forever when the active request is cancelled while its callback is still pending (never callsnext/resolve/reject), which blocked every subsequent request routed through the interceptor. - Fix
ErrorInterceptorHandler.reject(..., true)not continuing to following error interceptors in queued interceptors.
5.9.2
- Fixes
kIsWebacross different Flutter SDKs. - Provides
httpVersioninResponse.extrawhen usingIOHttpClientAdapter.
5.9.1
- Add
requestUrlandresponseUrlparameters toLogInterceptorfor more precise control over URL logging. - Fix
QueuedInterceptorhanging indefinitely when interceptor callbacks throw synchronous exceptions.
5.9.0
- Do not allow updating the error field after a cancel token has canceled.
- Allow passing an initial interceptors list to the constructor of
Interceptors. - Use
package:mimeto help determine thecontent-typeofMultipartFilebase on the providedfilename.
5.8.0+1
- Raise the version constraint of
dio_web_adapter.
5.8.0
- Update comments and strings with
MultipartFile. - Removes redundant warnings when composing request options on Web.
- Fixes boundary inconsistency in
FormData.clone(). - Support
FileAccessModeinDio.downloadandDio.downloadUrito change download file opening mode. - Fix
ListParamequality by using theDeepCollectionEquality. - Enables configuring the logging details of
DioExceptionglobally and locally. - Enables using
Dio.cloneto reuse base options, client adapter, interceptors, and transformer, in a newDioinstance.
5.7.0
- Graceful handling of responses with nonzero
Content-Length,Content-Typethat is json, and empty payload.- Empty responses are now transformed to
null.
- Empty responses are now transformed to
5.6.0
- Supports the WASM environment. Users should upgrade the adapter with
dart pub upgradeorflutter pub upgradeto use the WASM-supported version.
5.5.0+1
- Fix WASM compile errors after moving the web implementation to
dio_web_adapter.
5.5.0
- Raise the min Dart SDK version to 2.18.0.
- Add constructor for
DioExceptionType.badCertificate. - Create type alias
DioMediaTypeforhttp_parser'sMediaType. - Fix the type conversion regression when using
MultipartFile.fromBytes. - Split the Web implementation to
package:dio_web_adapter. - Add FusedTransformer for improved performance when decoding JSON.
- Set FusedTransformer as the default transformer.
- Improves
InterceptorState.toString(). - If the
CancelTokengot canceled before making requests, throws the exception directly rather than cut actual HTTP requests afterward. - Catch
MediaTypeparse exception inTransformer.isJsonMimeType. - Improves warning logs on the Web platform.
- Improves memory allocating when using
CancelToken.
5.4.3+1
- Fix type promotions for the UTF-8 encoder on previous Dart SDKs.
5.4.3
- Remove sockets detach in
IOHttpClientAdapter. - Allows to define
FormData.boundaryNameinstead of the default--dio-boundary-.
5.4.2+1
- Revert "Catch sync/async exceptions in interceptors' handlers".
5.4.2
- Fix
receiveTimeoutthrows exception after the request has been cancelled. - Catch sync/async exceptions in interceptors' handlers.
- Throws precise
StateErrorfor handler's duplicated calls.
5.4.1
- Provide fix suggestions for
dart fix. - Fix
receiveTimeoutfor streamed responses. - Fix cancellation for streamed responses and downloads when using
IOHttpClientAdapter. - Fix receive progress for streamed responses and downloads when using
IOHttpClientAdapter. - Support relative
baseUrlon the Web platform. - Avoid fake uncaught exceptions during debugging with IDEs.
5.4.0
- Improve
SyncTransformer's stream transform. - Allow case-sensitive header keys with the
preserveHeaderCaseflag through options. - Fix
receiveTimeoutfor theIOHttpClientAdapter. - Fix
receiveTimeoutfor thedownloadmethod ofDioForNative. - Improve the stream byte conversion.
5.3.4
- Raise warning for
Maps other thanMap<String, dynamic>when encoding request data. - Improve exception messages.
- Allow
ResponseDecoderandRequestEncoderto be async. - Ignores
Duration.zerotimeouts.
5.3.3
- Fix failing requests throw
DioExceptions with.unknowninstead of.connectionErroronSocketException. - Removes the accidentally added
optionsargument forOptions.compose. - Fix wrong formatting of multi-value header in
BrowserHttpClientAdapter. - Add warning in debug mode when trying to send data with a
GETrequest in web. - Reduce cases in which browsers would trigger a CORS preflight request.
- Add warnings in debug mode when using
sendTimeoutandonSendProgresswith an empty request body. - Fix
receiveTimeoutnot working correctly on web. - Fix
ImplyContentTypeInterceptorcan be removed byInterceptors.clear()by default.
5.3.2
- Revert removed
downloadforDioMixin. - Fix for
Dio.downloadnot cleaning the file on data handling error.
5.3.1
- Improve package descriptions and code formats.
- Improve comments.
- Fix error when cloning
MultipartFilefromFormDatawith regression test. - Deprecate
MultipartFileconstructor in favorMultipartFile.fromStream. - Add
FormData.clone.
5.3.0
- Remove
httpfromdev_dependencies. - Add support for cloning
MultipartFilefromFormData. - Only produce null response body when
ResponseType.json.
5.2.1+1
- Fix changelog on pub.dev.
5.2.1
- Revert changes to handling of
List<int>body data.
5.2.0+1
- Fix
DioErrorTypedeprecation hint.
5.2.0
- Make
LogInterceptorprints in DEBUG mode (when the assertion is enabled) by default. - Deprecate
DioErrorin favor ofDioException. - Fix
IOHttpClientAdapter.onHttpClientCreateRepeated calls IOHttpClientAdapter.onHttpClientCreatehas been deprecated and is scheduled for removal in Dio 6.0.0 - Please use the replacementIOHttpClientAdapter.createHttpClientinstead.- Using
CancelTokenno longer closes and re-createsHttpClientfor each request whenIOHttpClientAdapteris used. - Fix timeout handling for browser
receiveTimeout. - Improve performance when sending binary data (
List<int>/Uint8List).
5.1.2
- Allow
FormDatato send a null entry value as an empty string.
5.1.1
- Revert changes to
CancelToken.cancel()behavior, as a result theDioErrorprovided by theCancelToken.cancelErrordoes not contain useful information when the token was not used with a request. - Fix wrong
ListFormatbeing used for comparison during encoding ofFormDataandapplication/x-www-form-urlencoded, resulting in potential wrong output encoding forListFormat.multiandListFormat.multiCompatiblesince Dio 4.0.x. - Respect
Options.listFormatwhen encodingx-www-url-encodedcontent.
5.1.0
- Fix double-completion when using
connectionTimeouton web platform. - Allow defining adapter methods through their constructors.
- Fix
FormDataencoding regression for maps with dynamic keys, introduced in 5.0.3. - Mark several static
DioMixinfunctions as@internal. - Make
DioError.stackTracenon-nullable. - Ensure
DioError.stackTracealways points to the correct call site.
5.0.3
- Imply
List<Map>as JSON content inImplyContentTypeInterceptor. - Fix
FormDataencoding for collections and objects.
5.0.2
- Improve code formats according to linter rules.
- Remove the force conversion for the response body.
- Fix
DioErrorType.cancelinInterceptors. - Fix wrong encoding of collection query parameters.
- Fix "unsupported operation" error on web platform.
5.0.1
- Add
ImplyContentTypeInterceptoras a default interceptor. - Add
Headers.multipartFormDataContentTypefor headers usage. - Fix variable shadowing of
withCredentialsinbrowser_adapter.dart.
5.0.0
- Raise the min Dart SDK version to 2.15.0 to support
BackgroundTransformer. - Change
Dio.transformerfromDefaultTransformertoBackgroundTransformer. - Remove plain ASCII check in
FormData. - Allow asynchronous method with
savePath. - Allow
datain all request methods. - A platform independent
HttpClientAdaptercan now be instantiated by doingdio.httpClientAdapter = HttpClientAdapter();. - Add
ValidateCertificateto handle certificate pinning better. - Support
Content-Dispositionheader case sensitivity.
Breaking Changes
- The default charset
utf-8inHeaderscontent type constants has been removed. BaseOptions.setRequestContentTypeWhenNoPayloadhas been removed.- Improve
DioErrors. There are now more cases in which the inner original stacktrace is supplied. HttpClientAdaptermust now be implemented instead of extended.- Any classes specific to
dart:ioplatforms can now be imported viaimport 'package:dio/io.dart';. Classes specific to web can be imported viaimport 'package:dio/browser.dart';. connectTimeout,sendTimeout, andreceiveTimeoutare nowDurations.
4.0.6
- fix #1452
4.0.5
- require Dart
2.12.1which fixes exception handling for secure socket connections (#45214) - Only delete file if it exists when downloading.
- Fix
BrowserHttpClientAdaptercanceled hangs - Correct JSON MIME Type detection
- [Web] support send/receive progress in web platform
- refactor timeout logic
- use 'arraybuffer' instead of 'blob' for xhr requests in web platform
4.0.4
- Fix fetching null data in a response
4.0.3
- fix #1311
4.0.2
- Add QueuedInterceptor
- merge #1316 #1317
4.0.1
- merge pr #1177 #1196 #1205 #1224 #1225 #1227 #1256 #1263 #1291
- fix #1257
4.0.0
stable version
4.0.0-prev3
- fix #1091 , #1089 , #1087
4.0.0-prev2
- fix #1082 and # 1076
4.0.0-prev1
Interceptors: Add handler for Interceptor APIs which can specify
the subsequent interceptors processing logic more finely (whether to skip them or not).
4.0.0-beta7
- fix #1074
4.0.0-beta6
- fix #1070
4.0.0-beta5
- support ListParam
4.0.0-beta4
- fix #1060
4.0.0-beta3
- rename CollectionFormat to ListFormat
- change default value of Options.listFormat from
multiCompatibletomulti - add upload_stream_test.dart
4.0.0-beta2
- support null-safety
- add
CollectionFormatconfiguration in Options - add
fetchAPI for Dio - rename DioErrorType enums from uppercase to camel style
- rename 'Options.merge' to 'Options.copyWith'
3.0.10 2020.8.7
- fix #877 'dio.interceptors.errorLock.lock()'
- fix #851
- fix #641
3.0.9 2020.2.24
- Add test cases
3.0.8 2019.12.29
- Code style improvement
3.0.7 2019.11.25
- Merge #574 : fix upload image header error, support both oss and other server
3.0.6 2019.11.22
- revert #562, and fixed #566
3.0.5 2019.11.19
- merge #557 #531
3.0.4 2019.10.29
- fix #502 #515 #523
3.0.3 2019.10.1
- fix encode bug
3.0.2 2019.9.26
- fix #474 #480
3.0.2-dev.1 2019.9.20
- fix #470 #471
3.0.1 2019.9.20
- Fix #467
- Export
DioForNativeandDioForBrowserclasses.
3.0.0
New features
- Support Flutter Web.
- Extract CookieManager into a separate package(No need for Flutter Web).
- Provides HTTP/2.0 HttpClientAdapter.
Change List
-
Options.cookies -
Options.connectionTimeout;We should config connection timed out inBaseOptions. For keep-alive reasons, not every request requires a separate connection。 -
Options.followRedirects、Options.maxRedirects、Response.redirectsdon't make sense in Flutter Web,because redirection can be automatically handled by browsers. -
FormData.from,useFormData.fromMapinstead. -
Delete
Formdata.asBytes()、Formdata.asBytesAsync(), useFormdata.readAsBytes()instead. -
Delete
class,UploadFileInfoMultipartFileinstead. -
The return type of Interceptor's callback changes from
FutureOr<dynamic>toFuture. The reason is here. -
The type of
Response.headerschanges fromHttpHeaderstoHeaders, becauseHttpHeadersis in "dart:io" library which is not supported in Flutter Web.
2.1.16
Add deleteOnError parameter to downloadUri
2.1.14
- fix #402 #385 #422
2.1.13
- fix #369
2.1.12
- fix #367 #365
2.1.10
- fix #360
2.1.9
- support flutter version>=1.8 (fix #357)
2.1.8
- fix #354 #312
- Allow "delete" method with request body(#223)
2.1.7
- fix #321 #318
2.1.6
- fix #316
2.1.5
- fix #309
2.1.4
- Add
options.responseDecoder - Make DioError catchable by implementing Exception instead of Error
2.1.3
Add statusMessage attribute for Response and ResponseBody
2.1.2
First Stable version for 2.x
2.0
Refactor the Interceptors
- Support add Multiple Interceptors.
- Add Log Interceptor
- Add CookieManager Interceptor
API
- Support Uri
- Support
queryParametersfor all request API - Modify the
getAPI
Options
- Separate Options to three class: Options、BaseOptions、RequestOptions
- Add
queryParametersandcookiesfor BaseOptions
Adapter
- Abstract HttpClientAdapter layer.
- Provide a DefaultHttpClientAdapter which make http requests by
dart:io:HttpClient
0.1.8
- change file name "TransFormer" to "Transformer"
- change "dio.transFormer" to "dio.transformer"
- change deprecated "UTF8" to "utf8"
0.1.5
- add
clearmethod for dio instance
0.1.4
- fix
downloadbugs
0.1.3
- support upload files with Array
- support create
HttpClientby user self inonHttpClientCreate - support generic
- bug fix
0.0.1
- Initial version, created by Stagehand
