Белый экран при коде 200
Есть особый сорт аварии: всё живо, а смотреть не на что. Не 404, не 500. Сайт бодро отдаёт 200, файлы лежат где лежали, сервер дышит ровно. А в браузере белый лист. Чистый такой, аккуратный. Хоть заметки на нём пиши.
Дело было 16 августа, на этом самом сайте. Ломала связка. Кода я не знаю, в конфиги не лезу - за мной задача и приёмка, руки тут - МиниМы с агентами. Строку вписал агент, по собственному отчёту «чинится одной строкой». Белую страницу поймал я.
Что было видно глазами
Правка была «безобидная» по словам агента - теперь это слово в отчётах связки всегда в кавычках. После неё сайт открылся белым листом. Все ассеты отвечают 200. В консоли браузера ни одной красной строки про сеть, просто стили не применяются. Файлы приходят. Стилей нет. Сижу, моргаю.
Антон: очень быстро без диза вообще на белой странице
МиниМы: Смотрю. Все ассеты 200, ошибок в консоли нет - а стили не применяются.
*(пауза на разбор)*
МиниМы: Нашёл, косяк наш: types в nginx не добавляет тип - подменяет всю таблицу. Была карта на 900 типов, стала на один woff2. Откатываю.
Одна строка, которая это устроила
Агент полировал сайт и в конце отчёта дописал хвост: шрифт woff2 отдаётся как octet-stream, чинится одной строкой в custom-настройках nginx. Строку применили дословно из отчёта, через 43 секунды после того, как он закрыл задачу. В custom-конфиг vhost ушло:
types { font/woff2 woff2; }
Задача была смешная: чтобы шрифт .woff2 отдавался с правильным Content-Type. Логика железная - одному расширению один тип. Что тут вообще может пойти не так.
Корень: types не добавляет, а замещает
Директива types в nginx НЕ ДОБАВЛЯЕТ тип к таблице. Она ЗАМЕНЯЕТ таблицу целиком.
Была карта на ~900 типов из mime.types. Стала карта из ОДНОГО woff2. Всё остальное - css, js, svg, png - поехало как application/octet-stream. Шрифт, кстати, действительно починился. Ценой девятисот позиций. Размен, за который в приличном обществе бьют по рукам.
Почему все проверки были зелёными
Код ответа у всех файлов - 200. Ни одного битого запроса. При этом браузер в standards mode ОТКАЗЫВАЕТСЯ применять css с неправильным Content-Type (nosniff-поведение), и делает это молча. Файл скачался, код 200, стилей нет. Никто никому ничего не сказал.
Проверка «все ассеты отвечают 200» была честной и совершенно бесполезной. Мерили не то, что сломалось.
Правильный фикс
Не types, а location:
location ~* \.woff2$ { default_type font/woff2; }
Точечно для одного расширения, вся остальная таблица живёт своей жизнью и меня не трогает.
Правильная приёмка
Не «все ассеты 200», а код плюс Content-Type ПО КАЖДОМУ ТИПУ - по css, js, svg, шрифту, html:
curl -o /dev/null -w "%{http_code} %{content_type}"
Пять секунд работы. Ровно та проверка, которая показала бы octet-stream там, где положен text/css, до того как пошли радоваться шрифту.
Мораль в три слоя
Слой первый, технический: types{} в nginx - подмена, не добавка. Нужен один тип - бери location и default_type.
Слой второй, и он тут главный: «чинится одной строкой» - это гипотеза о механизме, а не готовая правка. Строка, которая чинит одно, может молча заменить собой карту на 900 позиций. Перед применением надо замерить СОСЕДЕЙ по классу, а не только цель. Правишь mime-тип шрифта - меряй все mime-типы. Иначе выходит ровно мой 3.14здец: цель зелёная, вокруг выжженное поле, а метрика радостно рапортует «двести».
Слой третий, про связку: «чинится одной строкой» из отчёта агента - это гипотеза, произнесённая уверенным голосом. Проверять соседей по классу - работа того, кто принимает. В тот вечер не проверил никто.
У меня на этот счёт есть правило, которое я повторяю всем подряд и которое сам же в тот вечер нарушил: «или хорошо или ни как». Быстрая правка «на посмотреть» - это и есть «ни как», только с гарантией 200 в ответе. Знать и делать - разные мышцы, и вторая у меня в тот вечер отдыхала.
Что осталось в чек-листе
Инцидент закрылся на откате минут за двадцать: строку убрали, сайт ожил, шрифт потом сделали через location. Но закрытый и понятый - это разные вещи, а бросать на середине я не умею. Молчание браузера меня тогда зацепило сильнее самой аварии: он всё получил, всё понял и решил ничего не применять, никому об этом не сообщив.
В сухом остатке одна команда, которая теперь стоит в приёмке после любой правки vhost: curl по каждому типу, а не по тому единственному файлу, ради которого всё затевалось. Пять секунд. В тот вечер они стоили белой страницы.
Антон Майорских, практик. Строку вписал агент, белую страницу увидел я, правило после разбора общее.