Сеть и HTTP
Что происходит между тем, как запрос ушёл из приложения, и тем, как пришёл ответ: методы, коды состояния, заголовки, кэширование, соединения — и множество способов, которыми этот обмен ломается на настоящем телефоне в настоящей сети.
Почему это важно. Мобильные сети медленные, теряют пакеты и постоянно пропадают. Приложение, написанное так, будто сеть — это обычный вызов функции, прекрасно работает по Wi-Fi за рабочим столом и разваливается в лифте, в электричке или в тот день, когда backend не упал, а всего лишь деградировал.
Что нужно понимать
- Что означает каждая часть запроса и какими из них вы управляете
- Что на самом деле обещает код состояния и как клиенту вести себя с каждым классом
- Какие сбои имеет смысл повторять, а какие нет
- На что уходит время запроса и какая его часть приходится не на сервер
- Что можно кэшировать, кому и на какой срок
Ключевые темы
Запрос
- Методы и что каждый из них должен означать — включая идемпотентность
- Заголовки, которые важны на практике: тип содержимого, авторизация, управление кэшем, условные запросы
- Строки запроса, параметры пути и тело запроса
Ответ
- Классы кодов состояния и те, в которых чаще всего ошибаются: 401 против 403, 404 против 204, 409, 422, 429
- Тела ошибок, на которые клиент может отреагировать, а не только показать их пользователю
- Согласование содержимого и сжатие
Соединения и задержки
- TLS, рукопожатия и почему переиспользование соединения значит больше, чем размер полезной нагрузки
- HTTP/2 и HTTP/3 в одном абзаце: мультиплексирование и head-of-line blocking
- Таймауты — на подключение, на чтение, общий — и осознанный выбор их значений
Отказы и восстановление
- Повторные попытки, backoff и jitter
- Почему повторять неидемпотентный запрос — это ошибка
- Отмена запроса: не платить за ответ, который никто не прочитает
- Отсутствие сети, нестабильная сеть и медленная сеть — три разные задачи
За пределами запроса и ответа
- WebSockets и server-sent events
- Опрос, long polling — и когда каждый из них честен
Уровни
| Уровень | Как это выглядит |
|---|---|
| Junior | Делает запросы, обрабатывает успех и одну общую ошибку, смотрит коды состояния в документации. |
| Middle | Различает классы ошибок и реагирует на них по-разному. Ставит таймауты, безопасно повторяет запросы, обрабатывает отмену. |
| Senior | Проектирует всё поведение клиента при сбоях — политику повторов, кэширование, работу без сети — и умеет найти, где на самом деле возникает задержка. |
Практика
Для начала
-
Обработайте каждый класс ошибок Возьмите экран, который показывает одну общую ошибку, и сделайте так, чтобы 401, 404, 422 и 500 вели себя по-разному и с пользой.
-
Добавьте таймауты Задайте каждому запросу осознанный таймаут и посмотрите, что делает интерфейс, когда он срабатывает.
-
Прочитайте трафик Посмотрите запросы собственного приложения в DevTools и объясните каждый из них.
Глубже
-
Повторяйте правильно Добавьте экспоненциальный backoff с jitter и убедитесь, что повторяются только идемпотентные запросы.
-
Кэшируйте по условию Используйте ETag или Last-Modified, чтобы неизменившиеся данные стоили одного обращения и ни байта данных.
-
Переживите плохую сеть Проверьте работу на медленных и рвущихся соединениях и почините то, что сломается.
Проверьте себя
- Какие запросы вашего приложения безопасно повторять — и откуда вы это знаете?
- Что делает приложение, когда сервер отвечает медленно, а не падает с ошибкой?
- Как вы выбираете значение таймаута?
- Что кэшируется в вашем приложении сегодня и кто это решил — вы или значение по умолчанию?
- Как отличить медленный сервер от медленной сети?
- Что происходит с запросом в полёте, когда пользователь уходит с экрана?
Материалы
- MDN HTTP reference — справочник по методам, заголовкам, кодам состояния и кэшированию. Точный, полный и такой, на котором заканчиваются споры.
- High Performance Browser Networking — книга Ильи Григорика, целиком доступная бесплатно. Главы про TCP, TLS и мобильные сети объясняют, на что уходит время запроса, лучше всего остального написанного на эту тему.
- HTTP Caching — заслуживает отдельного пункта: среди сетевых тем кэширование даёт наибольшую отдачу и чаще всего оказывается пропущенным.
- Timeouts, retries and backoff with jitter — из Amazon Builders' Library. Самое ясное объяснение того, почему наивные повторы только усугубляют аварию.
- dart:io HttpClient и package:http — то, что даёт сам Dart, и слой, которым на деле пользуется большинство проектов.