Что такое Interceptor (перехватчик) при работе с сетью в Flutter?

«Что такое Interceptor (перехватчик) при работе с сетью в Flutter?» — вопрос из категории Сети, который задают на 29% собеседований Flutter Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Interceptor — это паттерн, позволяющий перехватывать и модифицировать HTTP-запросы и ответы на клиентской стороне. В Flutter он часто реализуется в HTTP-клиентах, таких как Dio или http, и действует как цепочка middleware.

Основные сценарии использования:

  1. Добавление общих заголовков: Автоматическое подставление токена авторизации.
  2. Логирование: Запись деталей запросов и ответов для отладки.
  3. Обработка ошибок: Глобальный перехват ошибок (например, 401 Unauthorized) для обновления токена и повторения запроса.
  4. Кеширование: Возврат закешированного ответа при определенных условиях.

Практический пример с Dio:

import 'package:dio/dio.dart';

final dio = Dio();

// Добавляем перехватчик для логирования и авторизации
dio.interceptors.add(
  InterceptorsWrapper(
    onRequest: (RequestOptions options, RequestInterceptorHandler handler) {
      // Логируем запрос
      print('[${options.method}] ${options.uri}');
      // Добавляем Bearer Token из локального хранилища
      final token = await SecureStorage().getToken();
      if (token != null) {
        options.headers['Authorization'] = 'Bearer $token';
      }
      return handler.next(options); // Продолжаем выполнение
    },
    onResponse: (Response response, ResponseInterceptorHandler handler) {
      print('Response Status: ${response.statusCode}');
      return handler.next(response);
    },
    onError: (DioException error, ErrorInterceptorHandler handler) async {
      print('Error: ${error.message}');
      // Пример: повтор запроса при 401 ошибке
      if (error.response?.statusCode == 401) {
        try {
          // Пытаемся обновить токен
          final newToken = await AuthService().refreshToken();
          // Обновляем заголовок в исходном запросе
          error.requestOptions.headers['Authorization'] = 'Bearer $newToken';
          // Повторяем оригинальный запрос
          final response = await dio.fetch(error.requestOptions);
          return handler.resolve(response);
        } catch (e) {
          return handler.next(error); // Пробрасываем ошибку дальше
        }
      }
      return handler.next(error);
    },
  ),
);

Можно добавлять несколько интерцепторов, и они будут выполняться в порядке добавления.