Каков правильный код ответа REST для действительного запроса, но пустые данные?

Например, вы запускаете запрос GET для users/9, но нет пользователя с идентификатором # 9. Какой лучший код ответа?

  • 200 OK
  • 202 Принято
  • 204 Нет содержимого
  • 400 Bad Request
  • 404 Не найдено

Ответ 1

TL; DR: использовать 404

Смотрите этот блог. Это очень хорошо объясняет.

Резюме комментариев блога на 204:

  1. 204 No Content не очень полезен в качестве кода ответа для браузера (хотя согласно спецификации HTTP браузеры должны понимать его как код ответа "не меняйте представление").
  2. 204 No Content, однако, очень полезен для веб-сервисов ajax, которые могут указывать на успех без необходимости что-либо возвращать. (Особенно в таких случаях, как DELETE или POST которые не требуют обратной связи).

Поэтому ответом на ваш вопрос является использование 404 в вашем случае. 204 - это специальный код ответа, который вы не должны часто возвращать в браузер в ответ на GET.

Другие коды ответов, которые даже менее подходят, чем 204 и 404:

  1. 200 должны быть возвращены с телом того, что вы успешно получили. Не подходит, когда сущность, которую вы выбираете, не существует.
  2. 202 используется, когда сервер начал работу над объектом, но объект еще не полностью готов. Конечно, дело не в этом. Вы не начали и не начнете создание пользователя 9 в ответ на запрос GET. Это нарушает все виды правил.
  3. 400 используется в ответ на плохо отформатированный HTTP-запрос (например, искаженные заголовки http, неправильно упорядоченные сегменты и т.д.). Это почти наверняка будет обработано любой платформой, которую вы используете. Вам не придется иметь дело с этим, если вы не пишете свой собственный сервер с нуля. Редактировать: более новые RFC теперь позволяют использовать 400 для семантически неверных запросов.

Википедия с описанием кодов состояния HTTP особенно полезна. Вы также можете увидеть определения в документе HTTP/1.1 RFC2616 на www.w3.org

Ответ 2

Я решительно выступаю против 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-запрос не дал никаких результатов. Он может выполнить эту работу, но есть много возможных технических причин, которые вызывают одно и то же исключение, которое тогда было бы ошибочно принято за допустимый результат.

Ответ 3

Сначала я думал, что 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

Немного предыстории:

  1. поиск возвращает массив, у него просто нет совпадений, но у него есть содержимое: пустой массив.

  2. 404, конечно, лучше всего известен по URL, которые не поддерживаются запрошенным сервером, но отсутствующий ресурс фактически тот же.
    Несмотря на то, что /users/:name совпадает с users/kyle, пользовательский Kyle не является доступным ресурсом, поэтому 404 по-прежнему применяется. Это не поисковый запрос, это прямая ссылка по динамическому URL, так что 404 это так.

Во всяком случае, мои два цента :)

Ответ 4

Если он ожидает, что ресурс существует, но он может быть пустым, я бы сказал, что было бы проще просто получить 200 OK с представлением, указывающим, что предмет пуст.

Итак, я предпочел бы, чтобы/вещи возвращали 200 OK с { "Items": []}, чем 204, где ничего нет, потому что таким образом коллекция с 0 элементами может обрабатываться точно так же, как коллекция с одним или несколькими элементами в нем.

Я просто оставил 204 No Content для PUT и DELETE, где может быть и то, что действительно нет полезного представления.

В случае, если /thing/ 9 действительно не существует, подходит 404.

Ответ 5

В предыдущих проектах я использовал 404. Если нет пользователя 9, то объект не был найден. Поэтому 404 Not Found подходит.

Для объекта существует, но данных нет, 204 Нет содержимого. Я думаю, что в вашем случае объект не существует, хотя.

Ответ 6

Согласно w3 post,

200 OK

Запрос преуспел. Информация, возвращаемая с ответом, зависит от метода, используемого в запросе

202 Принято

Запрос принят для обработки, но обработка не завершена.

204 Нет содержимого

Сервер выполнил запрос, но ему не нужно возвращать тело сущности и может захотеть вернуть обновленную метаинформацию.

400 Плохой запрос

Запрос не может быть понят сервером из-за неправильного синтаксиса. Клиент НЕ ДОЛЖЕН повторять запрос без изменений

401 Несанкционированный

Запрос требует аутентификации пользователя. Ответ ДОЛЖЕН включать поле заголовка WWW-Authenticate

404 Не найдено

Сервер не нашел ничего, что соответствовало бы Request-URI. Не указывается, является ли условие временным или постоянным.

Ответ 7

Чтобы обобщить или упростить,

2xx: Необязательные данные: сформированный URI: критерии не являются частью URI: если критерии являются необязательными, которые могут быть указаны в @RequestBody, а @RequestParam должны приводить к 2xx. Пример: фильтр по имени/статусу

4xx: ожидаемые данные: неверно сформированный URI: критерии являются частью URI: если критерии обязательны, которые могут быть указаны только в @PathVariable, то это должно привести к 4xx. Пример: поиск по уникальному идентификатору.

Таким образом, для заданной ситуации: "Пользователи/9" будут 4xx (возможно, 404) Но для "users? Name = superman" должно быть 2xx (возможно, 204)

Ответ 8

Есть два вопроса. Один в заголовке и один в примере. Я думаю, что это частично привело к количеству споров о том, какой ответ подходит.

В заголовке вопроса запрашиваются пустые данные. Пустые данные по-прежнему являются данными, но не совпадают с данными. Таким образом, это предполагает запрос набора результатов, т.е. Списка, возможно, от /users. Если список пуст, он по-прежнему является списком, поэтому наиболее подходящим является 204 (No Content). Вы только что попросили список пользователей и получили один, у него просто нет контента.

В представленном примере вместо этого запрашивается конкретный объект, пользователь, /users/9. Если пользователь # 9 не найден, объект пользователя не возвращается. Вы запросили определенный ресурс (объект пользователя) и не получили его, потому что он не был найден, поэтому подходит 404.

Я думаю, что это можно сделать, если вы можете использовать ответ так, как вы ожидали бы, не добавляя никаких условных операторов, а затем используйте 204, иначе используйте 404.

В моих примерах я могу перебирать пустой список, не проверяя, есть ли у него контент, но я не могу отображать данные объекта пользователя на нулевом объекте, не нарушая что-либо, или добавляя чек, чтобы узнать, является ли оно нулевым.

Конечно, вы можете вернуть объект, используя шаблон нулевого объекта, если это соответствует вашим потребностям, но это обсуждение для другого потока.

Ответ 9

Что существующие ответы не уточняют, так это то, что имеет значение, используете ли вы параметры пути или параметры запроса.

  • В случае параметров пути параметр является частью пути ресурса. В случае /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. Вот почему:

  • Вызовы унарных (1 результат) и n-арных (n результатов) методов не должны изменяться без уважительной причины. Мне нравится иметь одинаковые коды ответов, если это возможно. Число ожидаемых результатов, конечно, является разницей, скажем, вы ожидаете, что тело будет объектом (унарным) или массивом объектов (n-арным).
  • Для n-a я бы возвратил массив, и в случае отсутствия результатов я бы не возвратил никакого набора (без документа), я бы возвратил пустой набор (пустой документ, как пустой массив в JSON или пустой элемент в XML). То есть это еще 200 но с нулевыми записями. Нет никакой причины помещать эту информацию в провод, кроме как в теле.
  • 204 как void метод. Я бы не использовал его для GET, только для POST, PUT и DELETE. Я делаю исключение в случае GET где идентификаторы являются параметрами запроса, а не параметрами пути.
  • Отсутствие записи похоже на NoSuchElementException, ArrayIndexOutOfBoundsException или что-то в этом роде, вызванное тем, что клиент использует идентификатор, который не существует, поэтому это ошибка клиента.
  • С точки зрения кода, получение 204 означает дополнительную ветвь в коде, которой можно избежать. Это усложняет клиентский код, а в некоторых случаях также усложняет серверный код (в зависимости от того, используете ли вы монады сущностей/моделей или простые сущности/модели; и я настоятельно рекомендую держаться подальше от монад сущностей/моделей, это может привести к неприятным ошибкам, где, поскольку из монады вы думаете, что операция прошла успешно, и возвращайте 200 или 204, когда вы действительно должны были вернуть что-то еще).
  • Код клиента легче написать и понять, если 2xx означает, что сервер сделал то, что запросил клиент, а 4xx означает, что сервер не сделал то, что запросил клиент, и это ошибка клиента. Не предоставление клиенту записи о том, что клиент, запрошенный по идентификатору, является ошибкой клиента, потому что клиент запросил идентификатор, который не существует.

Последнее, но не менее важное: последовательность

  • 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, открывается совершенно другая банка червей.

Ответ 10

204 более уместно. Особенно, если у вас есть система оповещений, обеспечивающая безопасность вашего сайта, 404 в этом случае может вызвать путаницу, поскольку вы не знаете, что некоторые оповещения 404 - это ошибки бэкэнда или обычные запросы, но ответ пуст.

Ответ 12

Я бы сказал, ни то, ни другое не подходит. Как уже было сказано - например, @anneb, я тоже думаю, что часть проблем возникает из-за использования HTTP-кода ответа для передачи статуса, относящегося к службе RESTful. Все, что служба REST может сказать о своей собственной обработке, должно передаваться с помощью специальных кодов REST.

1

Я бы сказал, что если HTTP-сервер найдет какой-либо сервис, который готов ответить на запрос, который он отправил, он не должен отвечать HTTP 404 - в конце концов, что-то было найдено сервером - если только это явно не указано сервис, который обрабатывает запрос.

Предположим на минуту следующий URL: http://example.com/service/return/test.

  • Случай А заключается в том, что сервер "просто ищет файл в файловой системе". Если его нет, 404 правильно. То же самое верно, если он запрашивает какой-либо сервис для доставки именно этого файла, и этот сервис сообщает, что ничего с таким именем не существует.
  • В случае B сервер не работает с "настоящими" файлами, но на самом деле запрос обрабатывается какой-то другой службой, например какой-то системой шаблонов. Здесь сервер не может предъявлять никаких претензий о существовании ресурса, поскольку он ничего не знает о нем (если только об этом не сообщит служба, обрабатывающая его).

Без какого-либо ответа от сервиса, явно требующего другого поведения, HTTP-сервер может сказать только 3 вещи:

  • 503 если служба, которая должна обрабатывать запрос, не работает или не отвечает;
  • 200 иначе как HTTP-сервер может фактически удовлетворить запрос - независимо от того, что служба скажет позже;
  • 400 или 404 чтобы указать, что такой службы нет (в отличие от "существует, но в автономном режиме") и ничего больше не найдено.

2

Возвращаясь к рассматриваемому вопросу: я думаю, что самым чистым подходом было бы не использовать HTTP-код ответа вообще, кроме как сказано ранее. Если служба присутствует и отвечает, HTTP-код должен быть 200. Ответ должен содержать статус, возвращенный службой в отдельном заголовке - здесь служба может сказать

  • REST:EMPTY например, если его попросили найти что-нибудь. и это исследование вернулось пустым;
  • REST:NOT FOUND если его спросили специально для чего-либо. "ID-like" - будь то имя файла или ресурс по идентификатору или записи № 24 и т.д. - и этот конкретный ресурс не был найден (обычно один конкретный ресурс был запрошен и не найден);
  • REST:INVALID если какая-либо часть запроса, которую он отправил, не распознается службой.

(обратите внимание, что я поставил перед ними префикс "REST:", чтобы отметить тот факт, что хотя они могут иметь те же значения или формулировку, что и коды ответов HTTP, они полностью отличаются)

3

Давайте вернемся к указанному выше 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 если она запланирована на более позднее время.

4

Это различие намного чище, чем смешивание двух разных вещей. Это также облегчит отладку и лишь немного усложнит обработку.

  • Если возвращается HTTP 404, сервер говорит мне: "Я понятия не имею, о чем ты говоришь". Хотя REST-часть моего запроса может быть совершенно нормальной, я ищу par'Mach во всех неправильных местах.
  • С другой стороны, HTTP 200 и REST: ERR говорят мне, что я получил услугу, но сделал что-то не так в своем запросе к службе.
  • Из HTTP 200 и REST: EMPTY я знаю, что ничего плохого не сделал - правильный сервер, сервер нашел сервис, правильный запрос к сервису - но результат поиска пуст.

Резюме

Проблема и обсуждение вытекают из того факта, что коды ответов HTTP используются для обозначения состояния службы, результаты которой обслуживаются HTTP, или для обозначения sth. это не входит в объем самого HTTP-сервера. Из-за этого несоответствия на вопрос невозможно ответить, и все мнения подлежат большому обсуждению.

Состояние запроса, обработанного службой, а не сервером HTTP, ДЕЙСТВИТЕЛЬНО НЕ ДОЛЖНО (RFC 6919) быть задано кодом ответа HTTP. Код HTTP СЛЕДУЕТ (RFC 2119) содержать только информацию, которую сервер HTTP может предоставить из своей собственной области: а именно, была ли найдена служба для обработки запроса или нет.

Вместо этого СЛЕДУЕТ использовать другой способ сообщить потребителю о состоянии запроса службе, которая фактически обрабатывает запрос. Мое предложение сделать это через специальный заголовок. В идеале как заголовок, так и его содержимое следуют стандарту, который облегчает потребителям работу с этими ответами.

Ответ 13

Почему бы не использовать 410? Он предполагает, что запрашиваемый ресурс больше не существует, и ожидается, что клиент никогда не сделает запрос для этого ресурса в вашем случае users/9.

Вы можете найти более подробную информацию о 410 здесь: https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

Ответ 14

Согласно 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-запросе с пустым результатом. (Пример: список без результата для определенного фильтра)

Ответ 15

Кодировать содержимое ответа с общим перечислением, которое позволяет клиенту соответственно включать его и вилку. Я не уверен, как ваш клиент будет отличать разницу между "не найденными данными" 404 и "веб-ресурс не найден" 404? Вы не хотите, чтобы кто-то просматривал пользователя Z/9, и клиент удивился, как будто запрос был действительным, но не было возвращено данных.

Ответ 16

Посмотрев вопрос, вы не должны использовать 404 почему?

На основании RFC 7231 правильный код статуса - 204

В ответах выше я заметил одно небольшое недоразумение:

1.- ресурс есть: /users

2.- /users/8 - это не ресурс, это: ресурс /users с параметром маршрута 8, возможно, потребитель не может заметить это и не знает разницы, но издатель знает и должен это знать!... поэтому он должен вернуть точный ответ для потребителей. период.

так:

Основано на RFC: 404 неверно, потому что ресурсы /users найдены, но логика, выполненная с использованием параметра 8, не нашла никакого content для возврата в качестве ответа, поэтому правильный ответ: 204

Главное здесь: 404 даже не был найден ресурс для обработки внутренней логики

204 - это: Я нашел ресурс, логика была выполнена, но я не нашел никаких данных, используя ваши критерии, указанные в параметре маршрута, поэтому я не могу ничего вам вернуть. Извините, проверьте ваши критерии и позвоните мне снова.

200: хорошо, я нашел ресурс, логика была выполнена (даже когда я ничего не должен возвращать), возьмите его и используйте по своему желанию.

205: (лучший вариант ответа GET) Я нашел ресурс, логика была выполнена, у меня есть некоторый контент для вашего пользователя, ну, кстати, если вы собираетесь поделиться этим в представлении, обновите представление до показать это.

Надеюсь, поможет.