Как отменить HTTP-запрос при использовании Dio в Dart/Flutter?

«Как отменить HTTP-запрос при использовании Dio в Dart/Flutter?» — вопрос из категории Сети, который задают на 29% собеседований Flutter Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Для отмены запросов в Dio используется CancelToken. Это особенно полезно при уходе со страницы (в dispose) или при повторном вызове запроса.

Базовый пример отмены:

import 'package:dio/dio.dart';

class ApiService {
  final Dio _dio = Dio();
  CancelToken? _cancelToken;

  Future<Response> fetchUserData(String userId) async {
    // Создаём новый токен отмены для этого запроса
    _cancelToken = CancelToken();

    try {
      return await _dio.get(
        '/users/$userId',
        cancelToken: _cancelToken,
      );
    } on DioException catch (e) {
      if (CancelToken.isCancel(e)) {
        print('Запрос fetchUserData был отменён');
      }
      rethrow;
    }
  }

  void cancelRequest() {
    _cancelToken?.cancel('Запрос отменён пользователем');
    _cancelToken = null;
  }
}

Практическое использование в StatefulWidget:

class UserPage extends StatefulWidget {
  @override
  _UserPageState createState() => _UserPageState();
}

class _UserPageState extends State<UserPage> {
  final ApiService _api = ApiService();

  @override
  void initState() {
    super.initState();
    _loadData();
  }

  @override
  void dispose() {
    // Отменяем все pending-запросы при уничтожении виджета
    _api.cancelRequest();
    super.dispose();
  }

  Future<void> _loadData() async {
    // ... вызов _api.fetchUserData ...
  }
}

Важно: Один CancelToken можно передать в несколько запросов, и вызов cancel() прервёт их все. Это удобно для групповой отмены.