Настройка мониторинга сетевых ошибок (Network Error Monitoring) в мобильном приложении
Продакшн-приложение без мониторинга сетевых ошибок — это когда о проблеме узнают из отзывов в App Store. Типичная ситуация: бэкенд вернул 502 в 3:00 ночи, 8% пользователей получили пустой экран, часть из них удалили приложение. В Sentry это было бы событием с полным контекстом: устройство, версия ОС, endpoint, статус ответа, тело ошибки.
Что мониторить
Сетевые ошибки делятся на категории с разной критичностью:
| Тип ошибки | Пример | Приоритет |
|---|---|---|
| Connectivity | Network request failed, timeout |
Высокий — пользователь не может работать |
| 4xx клиентские | 401, 403, 404, 422 | Средний — часто ожидаемые ошибки |
| 5xx серверные | 500, 502, 503, 504 | Высокий — проблема на бэкенде |
| Parse error | JSON decode failure | Высокий — breaking change в API |
| SSL/TLS | Certificate pinning failure | Критический — возможная атака |
Sentry для React Native: перехват сетевых запросов
@sentry/react-native автоматически перехватывает fetch и XMLHttpRequest через патч глобальных объектов. По умолчанию включает Performance трейсы для HTTP-запросов, но не логирует ошибки автоматически:
import * as Sentry from '@sentry/react-native';
Sentry.init({
dsn: 'https://[email protected]/yyy',
tracesSampleRate: 0.1, // 10% запросов трейсим для Performance
integrations: [
new Sentry.ReactNativeTracing({
traceFetch: true,
traceXHR: true,
// Не включать sensitive endpoints в трейсы
tracingOrigins: ['api.yourapp.com', 'cdn.yourapp.com'],
}),
],
});
Для явного логирования сетевых ошибок — обёртка над fetch:
export async function monitoredFetch(
url: string,
options?: RequestInit
): Promise<Response> {
const startTime = Date.now();
try {
const response = await fetch(url, options);
const duration = Date.now() - startTime;
if (!response.ok) {
Sentry.captureMessage(`HTTP ${response.status}: ${url}`, {
level: response.status >= 500 ? 'error' : 'warning',
extra: {
status: response.status,
duration,
method: options?.method ?? 'GET',
endpoint: new URL(url).pathname,
},
fingerprint: [`http-${response.status}`, new URL(url).pathname],
});
}
return response;
} catch (error) {
Sentry.captureException(error, {
extra: { url, duration: Date.now() - startTime },
tags: { error_type: 'network_connectivity' },
});
throw error;
}
}
fingerprint — критически важен. Без него Sentry создаёт отдельный ишью для каждого URL с ошибкой. С fingerprint ['http-500', '/api/orders'] все 500-е ошибки на /api/orders группируются в один ишью.
Breadcrumbs: контекст перед ошибкой
Breadcrumbs показывают, что происходило до сетевой ошибки: какие экраны открывал пользователь, какие действия совершал:
// Добавляем breadcrumb при навигации
navigation.addListener('state', (e) => {
Sentry.addBreadcrumb({
category: 'navigation',
message: `Navigate to ${e.data.state.routes[e.data.state.index].name}`,
level: 'info',
});
});
По умолчанию хранятся последние 100 breadcrumbs. Для длинных сессий — достаточно.
Детект потери соединения
Offline-ошибки нужно отделить от серверных. Пользователь в метро — не проблема бэкенда:
import NetInfo from '@react-native-community/netinfo';
let isConnected = true;
NetInfo.addEventListener(state => { isConnected = state.isConnected ?? true; });
// В monitoredFetch, при catch:
if (!isConnected) {
// Не отправляем в Sentry — это ожидаемый offline
throw new OfflineError('No network connection');
}
// Иначе — реальная ошибка, логируем
Sentry.captureException(error, { tags: { connectivity: 'online' } });
Алертинг
Sentry Alerts по условию: count(event) > 50 per 5min для http-500 → Slack/PagerDuty. Error rate выше baseline → alert. Для продакшн это должно работать 24/7.
Оценка
Настройка Sentry с монитором сетевых запросов, fingerprinting, offline-детектом и алертами: 1–2 недели.







