Налаштування Dio для мережевих запитів у Flutter-додатках
Пакет http з екосистеми Dart охоплює базові потреби, але продакшн-додатки швидко стикаються з завданнями, які він розв'язує незручно: перехоплювачі авторизації, автоматичний retry, логування, скасування запитів, завантаження multipart-файлів з прогресом. Dio розв'язує все це з коробки.
Встановлення та базова конфігурація
dependencies:
dio: ^5.4.0
Створіть singleton через get_it або riverpod:
final dio = Dio(BaseOptions(
baseUrl: 'https://api.example.com/v1',
connectTimeout: const Duration(seconds: 10),
receiveTimeout: const Duration(seconds: 30),
headers: {'Accept': 'application/json'},
));
Перехоплювачі — ключова частина налаштування
Auth перехоплювач додає токен до кожного запиту та обробляє 401:
class AuthInterceptor extends Interceptor {
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
final token = tokenStorage.accessToken;
if (token != null) {
options.headers['Authorization'] = 'Bearer $token';
}
handler.next(options);
}
@override
void onError(DioException err, ErrorInterceptorHandler handler) async {
if (err.response?.statusCode == 401) {
try {
await tokenStorage.refresh();
// Повторюємо оригінальний запит з новим токеном
final opts = err.requestOptions;
opts.headers['Authorization'] = 'Bearer ${tokenStorage.accessToken}';
final response = await dio.fetch(opts);
handler.resolve(response);
return;
} catch (_) {
// refresh failed — logout
}
}
handler.next(err);
}
}
Логування в режимі dev:
if (kDebugMode) {
dio.interceptors.add(LogInterceptor(
requestBody: true,
responseBody: true,
logPrint: (o) => debugPrint(o.toString()),
));
}
Retry перехоплювач для мережевих помилок — використовуйте dio_smart_retry:
dio.interceptors.add(RetryInterceptor(
dio: dio,
retries: 3,
retryDelays: [
Duration(seconds: 1),
Duration(seconds: 2),
Duration(seconds: 3),
],
));
Завантаження файлів та скасування запитів
// Multipart завантаження з прогресом
final formData = FormData.fromMap({
'file': await MultipartFile.fromFile(filePath, filename: 'photo.jpg'),
});
await dio.post('/upload', data: formData,
onSendProgress: (sent, total) {
progress.value = sent / total;
},
);
// Скасування запиту
final cancelToken = CancelToken();
dio.get('/data', cancelToken: cancelToken);
// Пізніше:
cancelToken.cancel('User navigated away');
CancelToken є обов'язковим для запитів, привязаних до життєвого циклу віджета. Незаперечення запитів у dispose() — утечка пам'яті та можливий setState після dispose.
Обробка помилок
DioException містить type — важливо розрізняти:
-
DioExceptionType.connectionTimeout— немає інтернету або сервер недоступний -
DioExceptionType.badResponse— сервер повернув 4xx/5xx -
DioExceptionType.cancel— запит скасовано
Обгорніть у domain-шар, щоб не тягти Dio-залежність у BLoC/Cubit:
Future<Either<Failure, T>> safeCall<T>(Future<T> Function() request) async {
try {
return Right(await request());
} on DioException catch (e) {
return Left(NetworkFailure.fromDioException(e));
}
}
Терміни
Базове налаштування Dio з auth-перехоплювачем та логуванням: 4–8 годин. З retry, обробкою помилок та інтеграцією архітектури (BLoC, Riverpod): 1–2 дні. Ціна розраховується індивідуально.







