Например, вы запускаете запрос GET для users/9
, но нет пользователя с идентификатором # 9.
Какой лучший код ответа?
- 200 OK
- 202 Принято
- 204 Нет содержимого
- 400 Bad Request
- 404 Не найдено
Например, вы запускаете запрос GET для users/9
, но нет пользователя с идентификатором # 9.
Какой лучший код ответа?
TL; DR: использовать 404
Смотрите этот блог. Это очень хорошо объясняет.
Резюме комментариев блога на 204
:
204 No Content
не очень полезен в качестве кода ответа для браузера (хотя согласно спецификации HTTP браузеры должны понимать его как код ответа "не меняйте представление").204 No Content
, однако, очень полезен для веб-сервисов ajax, которые могут указывать на успех без необходимости что-либо возвращать. (Особенно в таких случаях, как DELETE
или POST
которые не требуют обратной связи). Поэтому ответом на ваш вопрос является использование 404
в вашем случае. 204
- это специальный код ответа, который вы не должны часто возвращать в браузер в ответ на GET
.
Другие коды ответов, которые даже менее подходят, чем 204
и 404
:
200
должны быть возвращены с телом того, что вы успешно получили. Не подходит, когда сущность, которую вы выбираете, не существует.202
используется, когда сервер начал работу над объектом, но объект еще не полностью готов. Конечно, дело не в этом. Вы не начали и не начнете создание пользователя 9 в ответ на запрос GET
. Это нарушает все виды правил.400
используется в ответ на плохо отформатированный HTTP-запрос (например, искаженные заголовки http, неправильно упорядоченные сегменты и т.д.). Это почти наверняка будет обработано любой платформой, которую вы используете. Вам не придется иметь дело с этим, если вы не пишете свой собственный сервер с нуля. Редактировать: более новые RFC теперь позволяют использовать 400 для семантически неверных запросов.Википедия с описанием кодов состояния HTTP особенно полезна. Вы также можете увидеть определения в документе HTTP/1.1 RFC2616 на www.w3.org
Я решительно выступаю против 404 в пользу 204 или 200 с пустыми данными.
Запрос был получен и обработан надлежащим образом - он вызывал код приложения на сервере, поэтому нельзя сказать, что это была ошибка клиента, и, следовательно, весь класс кодов ошибок клиента (4xx) не подходит.
Более того, 404 может произойти по ряду технических причин. Например. приложение временно деактивировано или удалено на сервере, проблемы с прокси-соединением и многое другое. Поэтому клиент не может отличить 404, что означает "пустой набор результатов" и 404, что означает, что "служба не может быть найдена, повторите попытку позже".
Это может быть фатальным: представьте себе учетную службу в вашей компании, в которой перечислены все сотрудники, которые получают ежегодный бонус. К сожалению, один раз, когда он называется, он возвращает 404. Означает ли это, что никто не должен получать бонус или что приложение в настоящее время недоступно для нового развертывания?
- > Для приложений, которые заботятся о качестве своих данных, 404, следовательно, в значительной степени не работает.
Кроме того, многие клиентские среды реагируют на 404, бросая исключение без дополнительных вопросов. Это заставляет клиентского разработчика поймать это исключение, оценить его, а затем принять решение на основании этого, следует ли его регистрировать как ошибку, которая подхвачена, например, компонент мониторинга или игнорировать его. Мне это тоже не кажется приятным.
Единственное преимущество 404 над 204 заключается в том, что он может вернуть объект ответа, который может содержать некоторую информацию о том, почему запрошенный ресурс не найден. Но если это действительно актуально, то можно также рассмотреть возможность использования ответа 200 OK и разработать систему таким образом, чтобы допускать ошибки в данных полезной нагрузки. В качестве альтернативы, можно использовать полезную нагрузку ответа 404 для возврата структурированной информации вызывающему абоненту. Если он получает, например, html-страницу вместо XML или JSON, которую он может анализировать, то это хороший показатель того, что что-то техническое пошло не так, как ответ "нет результата", который может быть действительным с точки зрения вызывающего. Или для этого можно использовать заголовок ответа HTTP.
Тем не менее, я бы предпочел 204 или 200 с пустым ответом. Таким образом, статус технического выполнения запроса отделен от логического результата запроса. 2xx означает "техническое выполнение ok, это результат, с этим справиться".
Я думаю, что в большинстве случаев клиенту необходимо решить, допустим ли пустой результат или нет. Возвращая 404, несмотря на правильное техническое исполнение, клиент может решить, что случаи являются ошибками, которые просто не являются ошибками.
Другая быстрая аналогия: Возвращение 404 для "не найденного результата" похоже на то, что бросает исключение DatabaseConnectionException, если SQL-запрос не дал никаких результатов. Он может выполнить эту работу, но есть много возможных технических причин, которые вызывают одно и то же исключение, которое тогда было бы ошибочно принято за допустимый результат.
Сначала я думал, что 204 будет иметь смысл, но после обсуждений я считаю, что 404 - единственно верный правильный ответ. Рассмотрим следующие данные:
Пользователи: Джон, Питер
METHOD URL STATUS RESPONSE
GET /users 200 [John, Peter]
GET /users/john 200 John
GET /users/kyle 404 Not found
GET /users?name=kyle' 200 []
DELETE /users/john 204 No Content
Немного предыстории:
поиск возвращает массив, у него просто нет совпадений, но у него есть содержимое: пустой массив.
404, конечно, лучше всего известен по URL, которые не поддерживаются запрошенным сервером, но отсутствующий ресурс фактически тот же.
Несмотря на то, что /users/:name
совпадает с users/kyle
, пользовательский Kyle не является доступным ресурсом, поэтому 404 по-прежнему применяется. Это не поисковый запрос, это прямая ссылка по динамическому URL, так что 404 это так.
Во всяком случае, мои два цента :)
Если он ожидает, что ресурс существует, но он может быть пустым, я бы сказал, что было бы проще просто получить 200 OK с представлением, указывающим, что предмет пуст.
Итак, я предпочел бы, чтобы/вещи возвращали 200 OK с { "Items": []}, чем 204, где ничего нет, потому что таким образом коллекция с 0 элементами может обрабатываться точно так же, как коллекция с одним или несколькими элементами в нем.
Я просто оставил 204 No Content для PUT и DELETE, где может быть и то, что действительно нет полезного представления.
В случае, если /thing/ 9 действительно не существует, подходит 404.
В предыдущих проектах я использовал 404. Если нет пользователя 9, то объект не был найден. Поэтому 404 Not Found подходит.
Для объекта существует, но данных нет, 204 Нет содержимого. Я думаю, что в вашем случае объект не существует, хотя.
Согласно w3 post,
200 OK
Запрос преуспел. Информация, возвращаемая с ответом, зависит от метода, используемого в запросе
202 Принято
Запрос принят для обработки, но обработка не завершена.
204 Нет содержимого
Сервер выполнил запрос, но ему не нужно возвращать тело сущности и может захотеть вернуть обновленную метаинформацию.
400 Плохой запрос
Запрос не может быть понят сервером из-за неправильного синтаксиса. Клиент НЕ ДОЛЖЕН повторять запрос без изменений
401 Несанкционированный
Запрос требует аутентификации пользователя. Ответ ДОЛЖЕН включать поле заголовка WWW-Authenticate
404 Не найдено
Сервер не нашел ничего, что соответствовало бы Request-URI. Не указывается, является ли условие временным или постоянным.
Чтобы обобщить или упростить,
2xx: Необязательные данные: сформированный URI: критерии не являются частью URI: если критерии являются необязательными, которые могут быть указаны в @RequestBody, а @RequestParam должны приводить к 2xx. Пример: фильтр по имени/статусу
4xx: ожидаемые данные: неверно сформированный URI: критерии являются частью URI: если критерии обязательны, которые могут быть указаны только в @PathVariable, то это должно привести к 4xx. Пример: поиск по уникальному идентификатору.
Таким образом, для заданной ситуации: "Пользователи/9" будут 4xx (возможно, 404) Но для "users? Name = superman" должно быть 2xx (возможно, 204)
Есть два вопроса. Один в заголовке и один в примере. Я думаю, что это частично привело к количеству споров о том, какой ответ подходит.
В заголовке вопроса запрашиваются пустые данные. Пустые данные по-прежнему являются данными, но не совпадают с данными. Таким образом, это предполагает запрос набора результатов, т.е. Списка, возможно, от /users
. Если список пуст, он по-прежнему является списком, поэтому наиболее подходящим является 204 (No Content). Вы только что попросили список пользователей и получили один, у него просто нет контента.
В представленном примере вместо этого запрашивается конкретный объект, пользователь, /users/9
. Если пользователь # 9 не найден, объект пользователя не возвращается. Вы запросили определенный ресурс (объект пользователя) и не получили его, потому что он не был найден, поэтому подходит 404.
Я думаю, что это можно сделать, если вы можете использовать ответ так, как вы ожидали бы, не добавляя никаких условных операторов, а затем используйте 204, иначе используйте 404.
В моих примерах я могу перебирать пустой список, не проверяя, есть ли у него контент, но я не могу отображать данные объекта пользователя на нулевом объекте, не нарушая что-либо, или добавляя чек, чтобы узнать, является ли оно нулевым.
Конечно, вы можете вернуть объект, используя шаблон нулевого объекта, если это соответствует вашим потребностям, но это обсуждение для другого потока.
Что существующие ответы не уточняют, так это то, что имеет значение, используете ли вы параметры пути или параметры запроса.
/users/9
ответ должен быть 404
потому что этот ресурс не был найден. /users/9
- это ресурс, и результат унарный, или ошибки не существует. Это не монада./users?id=9
, ответ должен быть 204
потому что ресурс /users
был найден, но он не смог вернуть никаких данных. Ресурс /users
существуют, и результат n-арный, он существует, даже если он пуст. Если id
уникален, это монада. Использовать ли параметры пути или параметры запроса, зависит от варианта использования. Я предпочитаю параметры пути для обязательных, нормативных или идентифицирующих аргументов и параметры запроса для необязательных, ненормативных или атрибутивных аргументов (таких как разбиение на страницы, локаль сопоставления и прочее). В API REST я бы использовал /users/9
не /users?id=9
особенно из-за возможного вложения, чтобы получить "дочерние записи", такие как /users/9/ssh-keys/0
чтобы получить первый открытый ключ ssh или /users/9/address/2
чтобы получить третий почтовый адрес.
Я предпочитаю использовать 404. Вот почему:
204
как void
метод. Я бы не использовал его для GET
, только для POST
, PUT
и DELETE
. Я делаю исключение в случае GET
где идентификаторы являются параметрами запроса, а не параметрами пути.NoSuchElementException
, ArrayIndexOutOfBoundsException
или что-то в этом роде, вызванное тем, что клиент использует идентификатор, который не существует, поэтому это ошибка клиента.204
означает дополнительную ветвь в коде, которой можно избежать. Это усложняет клиентский код, а в некоторых случаях также усложняет серверный код (в зависимости от того, используете ли вы монады сущностей/моделей или простые сущности/модели; и я настоятельно рекомендую держаться подальше от монад сущностей/моделей, это может привести к неприятным ошибкам, где, поскольку из монады вы думаете, что операция прошла успешно, и возвращайте 200 или 204, когда вы действительно должны были вернуть что-то еще).Последнее, но не менее важное: последовательность
GET/users/9
PUT/users/9
и DELETE/users/9
PUT/users/9
и DELETE/users/9
уже должны вернуть 204
в случае успешного обновления или удаления. Так что они должны вернуть в случае, если пользователь 9 не существует? Нет смысла представлять одну и ту же ситуацию в виде разных кодов состояния в зависимости от используемого метода HTTP.
Кроме того, не нормативная, а культурная причина: если 204
используется для GET/users/9
следующая вещь, которая произойдет в проекте, это то, что кто-то думает, что возвращение 204
хорошо для n-арных методов. И это усложняет клиентский код, потому что вместо того, чтобы просто проверять 2xx
и затем декодировать тело, клиент теперь должен специально проверять 204
и в этом случае пропустить декодирование тела. Буд, что клиент делает вместо этого? Создать пустой массив? Тогда почему бы не иметь это на проводе? Если клиент создает пустой массив, 204 является формой глупого сжатия. Если клиент использует вместо этого null
, открывается совершенно другая банка червей.
204 более уместно. Особенно, если у вас есть система оповещений, обеспечивающая безопасность вашего сайта, 404 в этом случае может вызвать путаницу, поскольку вы не знаете, что некоторые оповещения 404 - это ошибки бэкэнда или обычные запросы, но ответ пуст.
Twitter использует 404 с пользовательским сообщением об ошибке типа "Данные не найдены".
Ссылка: https://developer.twitter.com/en/docs/basics/response-codes.html
Я бы сказал, ни то, ни другое не подходит. Как уже было сказано - например, @anneb, я тоже думаю, что часть проблем возникает из-за использования HTTP-кода ответа для передачи статуса, относящегося к службе RESTful. Все, что служба REST может сказать о своей собственной обработке, должно передаваться с помощью специальных кодов REST.
Я бы сказал, что если HTTP-сервер найдет какой-либо сервис, который готов ответить на запрос, который он отправил, он не должен отвечать HTTP 404 - в конце концов, что-то было найдено сервером - если только это явно не указано сервис, который обрабатывает запрос.
Предположим на минуту следующий URL: http://example.com/service/return/test
.
404
правильно. То же самое верно, если он запрашивает какой-либо сервис для доставки именно этого файла, и этот сервис сообщает, что ничего с таким именем не существует.Без какого-либо ответа от сервиса, явно требующего другого поведения, HTTP-сервер может сказать только 3 вещи:
503
если служба, которая должна обрабатывать запрос, не работает или не отвечает;200
иначе как HTTP-сервер может фактически удовлетворить запрос - независимо от того, что служба скажет позже;400
или 404
чтобы указать, что такой службы нет (в отличие от "существует, но в автономном режиме") и ничего больше не найдено.Возвращаясь к рассматриваемому вопросу: я думаю, что самым чистым подходом было бы не использовать HTTP-код ответа вообще, кроме как сказано ранее. Если служба присутствует и отвечает, HTTP-код должен быть 200. Ответ должен содержать статус, возвращенный службой в отдельном заголовке - здесь служба может сказать
REST:EMPTY
например, если его попросили найти что-нибудь. и это исследование вернулось пустым;REST:NOT FOUND
если его спросили специально для чего-либо. "ID-like" - будь то имя файла или ресурс по идентификатору или записи № 24 и т.д. - и этот конкретный ресурс не был найден (обычно один конкретный ресурс был запрошен и не найден);REST:INVALID
если какая-либо часть запроса, которую он отправил, не распознается службой.(обратите внимание, что я поставил перед ними префикс "REST:", чтобы отметить тот факт, что хотя они могут иметь те же значения или формулировку, что и коды ответов HTTP, они полностью отличаются)
Давайте вернемся к указанному выше URL-адресу и изучим случай B, где служба указывает HTTP-серверу, что он не обрабатывает этот запрос сам, а передает его в SERVICE
. HTTP выдает только то, что ему возвращает SERVICE
, он ничего не знает о части return/test
поскольку он обрабатывается SERVICE
. Если эта служба работает, HTTP должен вернуть 200
поскольку он действительно нашел что-то для обработки запроса.
Статус, возвращаемый SERVICE
(и который, как сказано выше, хотелось бы видеть в отдельном заголовке), зависит от того, какое действие фактически ожидается:
return/test
запрашивает определенный ресурс: если он существует, вернуть его со статусом REST:FOUND
; если этот ресурс не существует, верните REST:NOT FOUND
; это можно продлить, чтобы вернуть REST:GONE
если мы знаем, что он когда-то существовал и не вернется, и REST:MOVED
если мы знаем, что он перешел в Голливудreturn/test
считается операцией поиска или фильтрации: если набор результатов пуст, вернуть пустой набор в запрошенном типе и состояние REST:EMPTY
; набор результатов в запрашиваемом типе и статусе REST:SUCCESS
return/test
не является операцией, распознаваемой SERVICE
: верните REST:ERROR
если она полностью неверна (например, опечатка типа retrun/test
), или REST:NOT IMPLEMENTED
если она запланирована на более позднее время.Это различие намного чище, чем смешивание двух разных вещей. Это также облегчит отладку и лишь немного усложнит обработку.
Проблема и обсуждение вытекают из того факта, что коды ответов HTTP используются для обозначения состояния службы, результаты которой обслуживаются HTTP, или для обозначения sth. это не входит в объем самого HTTP-сервера. Из-за этого несоответствия на вопрос невозможно ответить, и все мнения подлежат большому обсуждению.
Состояние запроса, обработанного службой, а не сервером HTTP, ДЕЙСТВИТЕЛЬНО НЕ ДОЛЖНО (RFC 6919) быть задано кодом ответа HTTP. Код HTTP СЛЕДУЕТ (RFC 2119) содержать только информацию, которую сервер HTTP может предоставить из своей собственной области: а именно, была ли найдена служба для обработки запроса или нет.
Вместо этого СЛЕДУЕТ использовать другой способ сообщить потребителю о состоянии запроса службе, которая фактически обрабатывает запрос. Мое предложение сделать это через специальный заголовок. В идеале как заголовок, так и его содержимое следуют стандарту, который облегчает потребителям работу с этими ответами.
Почему бы не использовать 410? Он предполагает, что запрашиваемый ресурс больше не существует, и ожидается, что клиент никогда не сделает запрос для этого ресурса в вашем случае users/9
.
Вы можете найти более подробную информацию о 410 здесь: https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
Согласно RFC7231 - стр. 59 (https://tools.ietf.org/html/rfc7231#page-59) определение ответа кода состояния 404:
6.5.4. 404 Not Found Код состояния 404 (Not Found) указывает, что исходный сервер не нашел текущее представление для целевого ресурса или не хочет раскрыть, что он существует. Код состояния 404 не указывает, является ли это отсутствие представления временным или постоянным; код состояния 410 (пропал) предпочтительнее, чем 404, если исходный сервер знает, предположительно, через некоторые настраиваемые средства, что условие, вероятно, будет постоянным. Ответ 404 кэшируется по умолчанию; т.е. если иное не указано в определении метода или явных элементах управления кэшем (см. раздел 4.2.2 [RFC7234]).
И главное, что вызывает сомнения - это определение ресурса в контексте выше. Согласно тому же RFC (7231) определение ресурса:
Ресурсы: цель HTTP-запроса называется "ресурсом". HTTP не ограничивает природу ресурса; он просто определяет интерфейс, который может использоваться для взаимодействия с ресурсами. Каждый ресурс идентифицируется унифицированным идентификатором ресурса (URI), как описано в разделе 2.7 [RFC7230]. Когда клиент создает сообщение запроса HTTP/1.1, он отправляет целевой URI в одной из различных форм, как определено в (Раздел 5.3 [RFC7230]). Когда запрос получен, сервер восстанавливает эффективный URI запроса для целевого ресурса (раздел 5.5 [RFC7230]). Одна из целей разработки HTTP состоит в том, чтобы отделить идентификацию ресурса от семантики запроса, что стало возможным благодаря передаче семантики запроса в методе запроса (раздел 4) и нескольких полей заголовка, изменяющих запрос (раздел 5). Если существует конфликт между семантикой метода и любой семантикой, подразумеваемой самим URI, как описано в Разделе 4.2.1, семантика метода имеет приоритет.
Так что в моем понимании код состояния 404 не должен использоваться при успешном GET-запросе с пустым результатом. (Пример: список без результата для определенного фильтра)
Кодировать содержимое ответа с общим перечислением, которое позволяет клиенту соответственно включать его и вилку. Я не уверен, как ваш клиент будет отличать разницу между "не найденными данными" 404 и "веб-ресурс не найден" 404? Вы не хотите, чтобы кто-то просматривал пользователя Z/9, и клиент удивился, как будто запрос был действительным, но не было возвращено данных.
Посмотрев вопрос, вы не должны использовать 404
почему?
На основании RFC 7231 правильный код статуса - 204
В ответах выше я заметил одно небольшое недоразумение:
1.- ресурс есть: /users
2.- /users/8
- это не ресурс, это: ресурс /users
с параметром маршрута 8
, возможно, потребитель не может заметить это и не знает разницы, но издатель знает и должен это знать!... поэтому он должен вернуть точный ответ для потребителей. период.
так:
Основано на RFC: 404 неверно, потому что ресурсы /users
найдены, но логика, выполненная с использованием параметра 8
, не нашла никакого content
для возврата в качестве ответа, поэтому правильный ответ: 204
Главное здесь: 404
даже не был найден ресурс для обработки внутренней логики
204
- это: Я нашел ресурс, логика была выполнена, но я не нашел никаких данных, используя ваши критерии, указанные в параметре маршрута, поэтому я не могу ничего вам вернуть. Извините, проверьте ваши критерии и позвоните мне снова.
200
: хорошо, я нашел ресурс, логика была выполнена (даже когда я ничего не должен возвращать), возьмите его и используйте по своему желанию.
205
: (лучший вариант ответа GET) Я нашел ресурс, логика была выполнена, у меня есть некоторый контент для вашего пользователя, ну, кстати, если вы собираетесь поделиться этим в представлении, обновите представление до показать это.
Надеюсь, поможет.