Ответ
Interceptor — это паттерн, позволяющий перехватывать и модифицировать HTTP-запросы и ответы на клиентской стороне. В Flutter он часто реализуется в HTTP-клиентах, таких как Dio или http, и действует как цепочка middleware.
Основные сценарии использования:
- Добавление общих заголовков: Автоматическое подставление токена авторизации.
- Логирование: Запись деталей запросов и ответов для отладки.
- Обработка ошибок: Глобальный перехват ошибок (например, 401 Unauthorized) для обновления токена и повторения запроса.
- Кеширование: Возврат закешированного ответа при определенных условиях.
Практический пример с 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);
},
),
);
Можно добавлять несколько интерцепторов, и они будут выполняться в порядке добавления.
Ответ 18+ 🔞
Слушай, а вот это Interceptor — вообще тема, ебать мои старые костыли! Это такая штука, которая как хитрая жопа, встраивается в твой HTTP-клиент и может всё перехватить по дороге: запрос, ответ, ошибку. Представь, будто ты ставишь своего чела на почту, который все письма проверяет, что-то дописывает или, если пришла хуйня, сразу решает проблему, пока ты чай пьёшь.
Где это, блядь, пригождается, спросишь ты?
- Заголовки автоматом. Ну, ёпта, надоело же в каждом запросе вручную токен авторизации пихать? Interceptor сам его из хранилища достанет и прилепит. Красота.
- Логирование. Хочешь видеть, что куда ушло и что вернулось? Он всё запишет, как на духу. Для отладки — просто пиздец как удобно.
- Обработка косяков. Вот прилетает ошибка 401 (токен протух). Ты бы сам начинал писать гору кода, а interceptor может сам попробовать токен обновить и запрос повторить. Волнение ебать — снимает сразу.
- Кеширование. Можно научить его, чтобы он, если данные уже спрашивали, не лез в сеть, а отдавал из кэша. Умная жесть.
Смотри, как это на Dio выглядит, реальный пример:
import 'package:dio/dio.dart';
final dio = Dio();
// Вешаем нашего перехватчика-надзирателя
dio.interceptors.add(
InterceptorsWrapper(
onRequest: (RequestOptions options, RequestInterceptorHandler handler) async {
// Логируем, что за запрос пошёл
print('[${options.method}] ${options.uri}');
// Достаём токен (типа из безопасного хранилища)
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);
}
}
// Если это не 401, то тоже просто прокидываем ошибку дальше
return handler.next(error);
},
),
);
И таких перехватчиков можно навесить овердохуища — целую цепочку. Они будут работать один за другим, как на конвейере. Главное, код в блоках выше не трогай, там всё правильно. В общем, вещь мощная, жизнь упрощает конкретно.