Суть Читай реальные заголовки Cache-Control, логи edge и конфиг клиента SWR, затем предсказывай поведение свежести и фикс с наибольшим рычагом.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на senior-высоте — в орбите
◷ 14 min
SWR настраивается заголовком и парой строк клиентского конфига, а диагностируется в логе edge. Прочитай каждый, проследи, что кэш реально делает, и выбери фикс, который сеньор сделает первым.
Цель
Отработай цикл, который ты прогоняешь на каждом инциденте свежести: прочитай директиву или конфиг, предскажи таймлайн запроса и потянись к изменению, которое чинит поведение, а не симптом.
Сопоставляя заголовок с таймлайном, какая строка верна?
Heads-up Старше max-age, но внутри stale-while-revalidate ответ отдаётся stale немедленно и обновляется вне основного пути — без блокировки.
Heads-up stale-if-error=86400 ровно для этого: как только origin даёт ошибку, последняя хорошая копия отдаётся до 24ч вместо проброса 503.
Heads-up Внутри max-age запись свежая и отдаётся напрямую — вызова origin нет вообще. Условная ревалидация только после истечения, и даже тогда SWR делает её в фоне.
Лог показывает рост origin_inflight до сотен для одного ключа. Что происходит и какой фикс?
Heads-up Origin не течёт — источник в edge, который запускает обновление на каждый stale-hit. Перезапуск лишь сбросит счётчик до следующего истечения горячего ключа.
Heads-up Проблема не в окне SWR, а в некоалесцированных параллельных обновлениях. Его укорачивание вернуло бы пик синхронной ревалидации, не остановив стадо.
Heads-up stale-if-error помогает, когда origin даёт ошибку, но не останавливает edge от порождения сотен обновлений, которые ВЫЗЫВАЮТ ошибки. Корневой фикс — коалесцирование.
Пользователь оставил вкладку открытой на час, затем кликнул обратно в неё. Что делает клиент SWR, и что сделали бы два параллельных монтирования этого хука в одном тике?
Heads-up revalidateOnFocus работает stale-first: показывает кэшированные данные сразу и обновляет в фоне. Вся модель — никакой блокировки на обновлении.
Heads-up Кэш SWR глобально ключуется по ключу запроса; параллельные вызовы одного ключа внутри dedupingInterval коалесцируются на один in-flight запрос.
Heads-up revalidateOnFocus: true триггерит ревалидацию на focus окна в любом случае. Это и есть описанный триггер.
Сниппет 4 — кэширование проверки auth
GET /api/permissions/user-42Cache-Control: max-age=60, stale-while-revalidate=600
Викторина
Completed
Этот заголовок применён к по-пользовательскому эндпоинту прав. В чём дефект?
Heads-up Удлинение окна делает дыру в безопасности ХУЖЕ — stale «разрешено» отдаётся ещё дольше. Дефект — в кэшировании решения auth через SWR вообще.
Heads-up «В итоге» — и есть проблема: между отзывом и следующим пришедшим обновлением отозванный пользователь авторизован. Для контроля доступа «в итоге» — это уязвимость.
Heads-up stale-if-error заставляет аварии отдавать stale-«разрешено» ещё дольше. Ни одна stale-* директива не безопасна на решении об авторизации.
Итог
Каждый инцидент свежести читается в заголовке, логе или конфиге. Слоёный заголовок — это три вложенных окна: свежее, stale-while-revalidate, stale-if-error — и запрос трассируется по тому, в какое окно попадает его метка времени. Лог edge с растущим origin_inflight по одному ключу — это стадо фоновых обновлений, чинимое single-flight плюс джиттером, а не перезапуском. Клиентский конфиг воспроизводит модель: ревалидация на focus/reconnect работает stale-first, а dedupingInterval коалесцирует параллельные вызовы. И ни один заголовок нигде не делает SWR безопасным на решении об авторизации.