Dio — to potężny klient HTTP dla Dart i Flutter, stworzony przez chińskiego inżyniera Wenda Wanga. Biblioteka oferuje zaawansowane API z obsługą przechwytywaczy, FormData, przesyłania plików i anulowania żądań. Według danych pub.dev, 2025, Dio jest najpopularniejszym klientem HTTP w ekosystemie Flutter z ponad 8 tysiącami gwiazdek na GitHub.
Najważniejsze
Dio — to potężna biblioteka klienta HTTP dla języka Dart, najszerzej używana w aplikacjach Flutter. Dio zapewnia bogate API z obsługą przechwytywaczy, globalnej konfiguracji, transformatorów, FormData, przesyłania plików i elastycznego zarządzania limitami czasu, co czyni go głównym wyborem do komunikacji sieciowej w społeczności Flutter.
Biblioteka została stworzona przez Wenda Wanga w 2018 roku jako alternatywa dla wbudowanego dart:io HttpClient, który nie miał wielu nowoczesnych możliwości: jednolitej konfiguracji dla wszystkich żądań, przechwytywaczy i automatycznej serializacji. Do 2025 roku Dio wyprzedził pod względem popularności pakiet http od zespołu Dart, zajmując pierwsze miejsce wśród klientów HTTP w ekosystemie Flutter według danych pub.dev.
Dio obsługuje trzy adaptery: DartNativeAdapter (domyślnie na Android, iOS, Desktop), BrowserAdapter (w Web) i IOAdapter. Adapter jest automatycznie wybierany w zależności od platformy. Dio zapewnia również jednolity interfejs dla wszystkich platform Flutter — Android, iOS, Web, macOS, Windows i Linux.
Architektura Dio jest zbudowana na łańcuchu handlerów (handler chain). Każde żądanie przechodzi przez sekwencję interceptory, które mogą modyfikować żądanie (InterceptorsWrapper.onRequest), odpowiedź (onResponse) lub obsłużyć błąd (onError). Po interceptorach żądanie trafia do transformerów (Transformer), które przekształcają dane przed wysłaniem.
Instancja Dio jest konfigurowana przez obiekt BaseOptions zawierający podstawowy URL, domyślne nagłówki, limity czasu, typ odpowiedzi (JSON, stream, plain), parametry zapytania i format danych. Te ustawienia są stosowane do wszystkich żądań, ale mogą zostać nadpisane w konkretnym żądaniu. BaseOptions zapewnia jednolity punkt konfiguracji dla całej aplikacji, co upraszcza zmianę endpointu API lub dodawanie globalnych nagłówków.
Każde żądanie w Dio zwraca Response<T>, gdzie T — typ danych po przetworzeniu przez transformery. Domyślnie Dio automatycznie przekształca odpowiedź JSON na Map<String, dynamic>. Dla typowanych odpowiedzi używa się Dio wraz z pakietami serializacji: json_serializable, freezed lub built_value. Response zawiera data, headers, statusCode, requestOptions i dane dodatkowe.
Podstawowa konfiguracja jest tworzona przez Dio(BaseOptions). Można ustawić baseUrl dla wszystkich żądań, connectTimeout i receiveTimeout, nagłówki content-type i accept, a także queryParameters. Wszystkie te parametry są stosowane do każdego żądania, co eliminuje powielanie kodu i centralizuje zarządzanie ustawieniami sieciowymi.
Dio obsługuje dwa tryby serializacji: domyślny JSON (responseType: ResponseType.json) i strumieniowy (ResponseType.stream). W trybie stream Response.data zwraca ResponseBody, który można czytać częściami. Jest to wygodne w przypadku dużych plików payload, gdy pełne załadowanie do pamięci jest niepożądane. Tryb plain zwraca surowy ciąg znaków bez automatycznego parsowania JSON.
Interceptory — kluczowy mechanizm Dio do przechwytywania i modyfikacji żądań, odpowiedzi i błędów. Całkowicie zastępują one Interceptor z OkHttp i wtyczki z Ktor, ale z API specyficznym dla Dart i obsługą asynchroniczności przez Future. Interceptory można dodawać zarówno w globalnej konfiguracji Dio, jak i dla poszczególnych żądań.
| Metoda interceptora | Przeznaczenie | Przykład użycia |
|---|---|---|
| onRequest | Modyfikacja żądania przed wysłaniem | Dodawanie tokena autoryzacji |
| onResponse | Obsługa udanej odpowiedzi | Przekształcanie data na obiekty DTO |
| onError | Obsługa błędu żądania | Automatyczne ponawianie przy 503 |
Wbudowany LogInterceptor loguje każde żądanie: metodę, URL, nagłówki, treść i czas wykonania. Ma dwa tryby: compact (jedna linia na żądanie) i full (pełna informacja z treścią). LogInterceptor jest szczególnie przydatny podczas programowania, ale zaleca się wyłączanie go w wersjach release poprzez warunkowy import lub globalną flagę.
Niestandardowe interceptory tworzy się przez klasę InterceptorsWrapper. Można nadpisać jeden, dwa lub wszystkie trzy metody (onRequest, onResponse, onError). Dio wykonuje interceptory ściśle w kolejności ich dodawania do listy interceptors. Jeśli interceptator nie wywoła handler.next(), łańcuch zostaje przerwany, a odpowiedź/błąd nie dociera do aplikacji.
Do autoryzacji w Dio używa się interceptora dodającego token Bearer do nagłówka Authorization. Jeśli serwer zwróci 401, interceptor w onError próbuje odświeżyć token przez żądanie refresh i powtarza oryginalne żądanie z nowym tokenem. Ten wzorzec nazywa się token refresh interceptor i jest implementowany przez DioException ze sprawdzeniem response?.statusCode == 401.
Dio zapewnia wbudowaną obsługę logiki ponawiania poprzez pakiet dio_smart_retry lub niestandardowy RetryInterceptor. Ponawianie jest ważne dla aplikacji mobilnych: przy utracie połączenia na 2–3 sekundy Dio rzuca DioException z typem connectionTimeout lub connectionError. RetryInterceptor przechwytuje ten wyjątek i powtarza żądanie do 3 razy z opóźnieniem wykładniczym (1s, 2s, 4s), co zwiększa niezawodność aplikacji w warunkach niestabilnej sieci.
Rozważmy podstawowe żądanie GET przez Dio. Tworzy się instancję z BaseOptions, ustawia podstawowy URL i limity czasu. Żądanie jest wykonywane przez metodę get(), zwracającą Response z danymi w formacie Map.
final dio = Dio(BaseOptions(
baseUrl: 'https://api.github.com',
connectTimeout: Duration(seconds: 15),
receiveTimeout: Duration(seconds: 15),
headers: {
'Accept': 'application/vnd.github.v3+json',
},
))
final response = await dio.get('/users/octocat')
print(response.data['zaloguj'])
Dla żądania POST z treścią JSON przekazuje się obiekt Map lub niestandardowy DTO. Dio automatycznie serializuje Map do JSON przez jsonEncode. Dla typowanych DTO używa się opcji queryParameters, pola data lub niestandardowego Transformera.
final data = {
'name': 'my-project',
'description': 'Created via Dio',
'private': false,
}
final response = await dio.post(
'/user/repos',
data: data,
options: Options(
contentType: ContentType.json.value,
),
)
print(response.data['id'])
Niestandardowy interceptor dodaje token Bearer do każdego żądania. Metoda onRequest działa przed wysłaniem, modyfikując nagłówki. Przy odpowiedzi 401 interceptor może odświeżyć token i powtórzyć żądanie przez metodę dio.fetch(requestOptions).
class AuthInterceptor extends InterceptorsWrapper {
final String token
AuthInterceptor(this.token)
@override
void onRequest(
RequestOptions options,
RequestInterceptorHandler handler,
) {
options.headers['Authorization'] = 'Bearer $token'
handler.next(options)
}
}
dio.interceptors.add(AuthInterceptor('ghp_abc123'))
Dio upraszcza przesyłanie plików przez FormData. Do wysłania pliku tworzy się MultipartFile z File, Bytes lub AssetBundle. FormData automatycznie ustawia nagłówek multipart/form-data z prawidłową granicą i kodowaniem. Dio obsługuje postęp przesyłania przez onSendProgress.
Do pobierania plików używa się metody download(), która zapisuje strumień danych bezpośrednio do pliku. Dio obsługuje dokańczanie (resume) przerwanych pobierań poprzez nagłówek Range, co jest szczególnie przydatne w przypadku dużych plików. Postęp pobierania jest śledzony przez onReceiveProgress, umożliwiając wyświetlanie paska postępu w interfejsie.
final formData = FormData.fromMap({
'file': await MultipartFile.fromFile(
'/path/to/photo.jpg',
filename: 'photo.jpg',
),
'description': 'Profile photo',
})
await dio.post(
'/upload',
data: formData,
onSendProgress: (sent, total) {
final progress = sent / total * 100
print('Przesyłanie: $progress%')
},
)
// Pobieranie pliku
await dio.download(
'https://example.com/file.zip',
'/storage/emulated/0/Download/file.zip',
onReceiveProgress: (received, total) {
print('Pobieranie: ${received / total * 100}%')
},
)
Nieprawidłowa obsługa błędów — najczęstszy problem. Dio rzuca DioException (wcześniej DioError) przy wszelkich problemach: brak sieci, limit czasu, błędy HTTP 4xx/5xx. Wielu programistłow łapie tylko ogólny Exception, tracąc informację o typie błędu i możliwości jego niestandardowej obsługi. Używaj DioException.type do określenia przyczyny awarii.
Ignorowanie CancelToken prowadzi do wycieków żądań. Jeśli użytkownik opuści ekran, a żądanie nadal jest wykonywane, Dio zużywa zasoby i może próbować zaktualizować zniszczony State. Zawsze twórz CancelToken dla każdego żądania i anuluj go w dispose(). CancelToken generuje DioException z typem cancel, który należy poprawnie obsłużyć.
Brak logiki ponawiania dla tymczasowych awarii. Na urządzeniach mobilnych sieć jest często krótkotrwale niedostępna. Zaimplementuj interceptor z automatycznym ponawianiem żądania przy przekroczeniu limitu czasu lub odpowiedzi 503/502. Użyj RetryInterceptor z pakietu dio_smart_retry lub napisz niestandardowy interceptor z opóźnieniem wykładniczym między próbami.
Często zadawane pytania
Dio zapewnia interceptory, globalną konfigurację BaseOptions, FormData, postęp przesyłania i CancelToken. Pakiet http od zespołu Dart — minimalistyczny, bez przechwytywaczy i globalnej konfiguracji. Dio jest używany w dużych projektach, http — w prostych skryptach.
Dio domyślnie przekształca JSON na Map przez jsonDecode. Do typowanej serializacji używaj pakietów json_serializable lub freezed. Utwórz niestandardowy interceptor, który w onResponse przekształca response.data na DTO przez fromJson().
Utwórz CancelToken i przekazać go w opcjach żądania. Wywołanie token.cancel() przerywa żądanie i powoduje DioException z typem cancel. CancelToken obsługuje anulowanie kilku żądań jednocześnie, co jest wygodne do anulowania wszystkich żądań przy opuszczaniu ekranu.
Tak, Dio działa na wszystkich sześciu platformach Flutter: Android, iOS, Web, macOS, Windows i Linux. Dla każdej platformy używany jest adaptacyjny klient HTTP: DartNativeAdapter (platformy natywne) i BrowserAdapter (Web). Jednolity API dla wszystkich platform — kluczowa zaleta Dio w projektach Flutter.
Dio nie zarządza cookie automatycznie. Do obsługi cookie używa się pakietu dio_cookie_manager wraz z cookie_jar. CookieManager przechwytuje nagłówki Set-Cookie i Cookie oraz zapisuje ciasteczka w PersistCookieJar do automatycznego wysyłania w kolejnych żądaniach do tej samej domeny.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również