
Ошибка 400 Bad Request - это сервер, отказывающийся даже пытаться. Он посмотрел на то, что пришло, решил, что оно достаточно испорчено, чтобы не было смысла разбирать дальше, и вернул единственный код, который означает “это не тот запрос, который я могу прочитать”.
Это отказ иного рода, чем у большинства окружающих его ошибок. Ошибка 404 означает, что сервер прекрасно вас понял и по этому адресу у него ничего нет. Ошибка 403 означает, что он вас понял и делать этого не станет. Ошибка 400 означает, что он так и не дошёл до понимания: синтаксис был неверным, заголовок был испорчен, тело было не той формы, которую объявляет конечная точка. Запрос провалился ещё до того, как вопрос был задан.
Слово “клиент” здесь работает за многих
Любой справочник скажет вам, что 4xx - это ошибка клиента, и это технически верно и практически вводит в заблуждение. Клиент - это не вы. Клиент - это та программа, которая составила запрос, а на современном сайте это почти всегда JavaScript самой страницы.
Поэтому ошибка 400 на сайте, который вы посещаете, обычно означает, что их фронтенд построил запрос, который их бэкенд принимать не захотел. Чей-то сериализатор формы отправил дату в неправильном формате, вызов fetch отправил JSON, не сказав, что это JSON, строка запроса несла символ, который никто не экранировал. Код состояния винит клиента, и клиент этот - их.
Это важно, потому что переворачивает совет, который прилагается к большинству ошибок. При ошибке 500 вина очевидно на сервере, и сделать вы ничего не можете. При ошибке 400 вина звучит как ваша, что отправляет людей на двадцать минут чистить кэши и перенабирать адреса из-за бага, вызвать который они никак не могли.
Семейство 4xx, которое постоянно путают
- 400 Bad Request
- Запрос был испорчен. Сервер не смог разобрать его настолько, чтобы что-то с ним сделать, поэтому ни то, кто вы, ни то, что вы просили, вообще не рассматривалось
- 401 Unauthorized
- С запросом всё было в порядке. Вы не доказали, кто вы, и сервер хочет учётные данные
- 403 Forbidden
- С запросом всё было в порядке, и он знает, кто вы. Вам это не разрешено
- 404 Not Found
- С запросом всё было в порядке, и по этому адресу ничего нет
Строчка, которую стоит запомнить: только 400 говорит о форме запроса. Остальные три описывают корректно составленный запрос, упирающийся в стену дальше внутри, и именно поэтому 401 и 403 так часто меняют местами, а ни один из них никогда не путают с 400. Если вы получаете 400, перестаньте спрашивать о правах и начните спрашивать, что на самом деле было отправлено.
Единственная ошибка 400, которую вы действительно можете исправить со своей стороны
Исключение есть, и оно достаточно частое, чтобы знать о нём прежде, чем списывать сайт как сломанный: запрос, заголовки которого слишком велики.
Куки - это заголовки. Сайт, накопивший их за несколько лет, или процедура входа, повторённая достаточно раз, чтобы нагромоздить состояние сессии, могут вытолкнуть блок заголовков за предел, который сервер готов читать. Большинство серверов отвечают на это ошибкой 400, иногда страницей с надписью “Request Header Or Cookie Too Large”, а часто вообще ничем.
Признак в том, что она ходит за вами по одному сайту и ни по какому другому, переживает перезагрузку страницы и мгновенно исчезает в приватном окне. Если это описывает то, что вы видите, удаление куки этого сайта исправит дело, и это единственная ошибка 400, где обычные народные средства оказываются настоящим ответом. Если приватное окно показывает ту же ошибку 400, дело не в этом, и никакая чистка её не тронет.
Если сайт ваш
Ответ, который получил пользователь, почти пуст по замыслу, поэтому причина лежит в том, что было отправлено, а не в том, что вернулось. Горстка вещей объясняет большинство таких случаев.
Испорченное или неверно набранное тело. Запрос POST, несущий JSON, который не разбирается,
или который разбирается и не соответствует схеме, по которой конечная точка проверяет. Часто это
поле со значением null там, где API объявил строку, или число, приходящее как "12", потому
что сериализатор формы превращает всё в строки.
Отсутствующий или неверный Content-Type. Тело, которое сервер с радостью принял бы,
отправленное без указания того, что это, или помеченное как text/plain, когда парсер хочет
application/json. Запрос корректен на вид и нечитаем для того, кому его читать.
Что-то в адресе, что так и не было экранировано. Голый пробел, залётный %, не являющийся
началом escape-последовательности, параметр запроса, несущий собственный адрес с собственным &.
Часть из них отвергается веб-сервером до того, как ваше приложение их вообще увидит, и поэтому
они не оставляют следа в журнале приложения.
Заголовки, которые не примет прокси. Случай с куки выше, но также и чрезмерно большой
заголовок Authorization или заголовок, несущий перевод строки. Такие обычно отклоняются на
краю, силами nginx или CDN, и возвращающаяся ошибка 400 принадлежит этому прокси, а не вам.
Эта последняя группа и есть причина, по которой ошибка 400 бывает по-настоящему невидимой изнутри. Если отказ случился до того, как запрос дошёл до вашего кода, в журнале приложения нет строки, которую можно было бы найти, и вы способны потратить полдня, ища баг там, куда ему никогда не позволяли добраться.
Почему ошибку 400 трудно преследовать задним числом
Ошибка 400 целиком является утверждением о запросе, которого больше не существует. К тому моменту, когда вам о ней расскажут, испорченное уже исчезло: у вас есть код состояния, приблизительное время и адрес, который прекрасно работает, когда вы набираете его сами, потому что сломалось то, что было в заголовке или в теле, а их из адресной строки не видно.
Воспроизвести её значит восстановить точный запрос, а это значит знать, что отправила страница, и это ровно то единственное, чего снимок экрана со страницей ошибки вам сказать не может.
Session Replay
Бесплатное расширение Chrome. Один клик на странице, которая ведёт себя неправильно, захватывает снимок экрана, консоль и сетевой журнал, и даёт вам ссылку для вставки в задачу.
Сетевой журнал здесь и есть весь смысл. Он содержит запрос, получивший ошибку 400, вместе с его методом, заголовками и телом, а это ровно тот материал, на который ошибка 400 и жалуется. Тот, кто возьмёт отчёт в работу, сможет прочитать, что было отправлено, а не догадываться, и обычно это и есть всё расследование.
В одном абзаце
Ошибка 400 Bad Request означает, что сервер не смог разобрать пришедшее и сдался прежде, чем рассматривать его, и это делает её единственной ошибкой 4xx, которая говорит о форме запроса, а не о правах или существовании. Её называют ошибкой клиента, но клиент обычно и есть JavaScript самого сайта, так что посетителю, как правило, чинить нечего, с одним настоящим исключением: блок куки или заголовков, разросшийся слишком сильно, что приватное окно подтверждает за секунды. Если сайт ваш, смотрите на то, что было отправлено: неразбираемое тело, отсутствующий content type, неэкранированный адрес или заголовок, который ваш прокси отверг ещё до того, как ваш код успел выполниться.