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

332

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

  • 200 ОК
  • 202 Принято
  • 204 Нет содержимого
  • ошибка 400, неверный запрос
  • 404 Не Найдено
IMB
источник
19
Подсказка: вы нашли пользователя 9?
Крис Пфол
42
Подсказка 2: Значит, пользователь 9 не найден ?
Томаш Нуркевич
18
@IMB, кто говорит 204? «Нет содержимого» означает, что искомая сущность существует, но не имеет представления. Например, если в блоге с идентификатором 15 нет комментариев, и вы не хотите возвращать пустой список для комментариев блога № 15: «/ blog / 15 / comments» вернет NoContent. С другой стороны, если блог 15 существует, «404 Not Found» является более подходящим.
Крис Пфол
12
@Crisfole, разве вы не имели в виду «С другой стороны, если блог 15 не существует,« 404 Not Found »более уместен»
gdoron поддерживает Monica
15
Я наверняка сделал @gdoron! :) Спасибо. К сожалению, я опоздал примерно на три года, чтобы отредактировать это и исправить.
Крис Пфол

Ответы:

249

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

Крис Пфол
источник
8
Примечание: коды ответов в 200-х указывают на успех. Коды ответа в 400-х годах указывают на сбой. Сводка, пункты первая и вторая, касается 204кода ответа (без содержимого).
Крис Пфол
227
-1, поскольку я слишком категорически против 404 в качестве ответа на успешный вызов, который не имеет записей для возврата. Как разработчик, имеющий дело с API для не-веб-приложения, я потратил часы на то, чтобы связаться с разработчиками API, чтобы выяснить, почему конечной точки API, которую я вызывал, не существовало, а на самом деле это не имело данные для отчета. Что касается 204, который не особенно полезен для браузера, это немного похоже на то, как хвост машет собакой, поскольку большинство применений конечных точек API в нашей вселенной интеллектуальных устройств не основаны на браузере, а те, которые, вероятно, используют AJAX. Извините, что забрал очки, хотя.
Мэтт Кашатт
38
@ MatthewPatrickCashatt вы можете понизить голос, как вам угодно. Теперь я, наконец, понимаю, почему люди отвергают меня, но обоснование все еще неверно. При получении 404 это не означает, что маршрут не имеет смысла, это означает, что в этом месте нет ресурса. Полная остановка. Это верно, если вы запрашиваете /badurlили /user/9когда такого пользователя не существует. Разработчик может помочь, добавив более разумную фразу причины, чем «Не найдено», но это не обязательно.
Крис Пфол
19
@Crisfole Я склонен согласиться (хотя и не downvote, продолжайте читать), основаны от определения W3 из 404 , в частности The server has not found anything matching the Request-URI. Сервер веб-приложений фактически обнаружил действие, соответствующее Request-URI, а сервер базы данных - нет. Тем не менее, он также говорит This status code is commonly used when [...] no other response is applicable, так что я думаю, что это несколько подтверждает его использование (даже если я не согласен с / нравится).
Daevin
8
Я не думаю, что вы обращаете внимание на то, что я делаю: 404 опасно сбивает с толку. Полагаясь на то, что вызывающий абонент проверяет фразу причины или текст ответа, вы не доверяете коду состояния, и в этом случае это бесполезно.
Адриан Бейкер
364

Я категорически против 404 в пользу 204 или 200 с пустыми данными. Или, по крайней мере, следует использовать объект ответа с 404.

Запрос был получен и правильно обработан - он вызвал код приложения на сервере, поэтому нельзя сказать, что это была ошибка клиента, и поэтому весь класс кодов ошибок клиента (4xx) не подходит.

Что еще более важно, 404 может произойти по ряду технических причин. Например, приложение временно деактивировано или удалено на сервере, проблемы с подключением к прокси и так далее. Поэтому клиент не может различить 404, что означает «пустой набор результатов», и 404, что означает «служба не может быть найдена, повторите попытку позже».

Это может быть фатальным: представьте себе бухгалтерскую службу в вашей компании, в которой перечислены все сотрудники, которые должны получить ежегодный бонус. К сожалению, один раз, когда он вызывается, он возвращает 404. Означает ли это, что никто не должен получить бонус, или что приложение в настоящее время закрыто для нового развертывания?

-> Для приложений, которые заботятся о качестве своих данных, 404 без объекта ответа, таким образом, в значительной степени является запретом.

Кроме того, многие клиентские платформы отвечают на 404, выдавая исключение без дополнительных вопросов. Это вынуждает разработчика клиента перехватить это исключение, оценить его, а затем принять решение на основе этого: регистрировать ли его как ошибку, обнаруженную, например, компонентом мониторинга, или игнорировать ее. Это тоже не кажется мне симпатичным.

Преимущество 404 над 204 состоит в том, что он может возвращать объект ответа, который может содержать некоторую информацию о том, почему запрошенный ресурс не был найден. Но если это действительно актуально, то можно также рассмотреть возможность использования ответа «200 OK» и спроектировать систему таким образом, чтобы можно было реагировать на ошибки в данных полезной нагрузки. В качестве альтернативы можно использовать полезную нагрузку ответа 404 для возврата структурированной информации вызывающей стороне. Если он получает, например, html-страницу вместо XML или JSON, которую он может проанализировать, то это хороший индикатор того, что что-то техническое пошло не так, вместо ответа «нет результата», который может быть действительным с точки зрения вызывающего. Или для этого можно использовать заголовок ответа HTTP.

Тем не менее, я бы предпочел 204 или 200 с пустым ответом, хотя. Таким образом, статус технического выполнения запроса отделен от логического результата запроса. 2xx означает «техническое исполнение хорошо, это результат, разберитесь с ним».

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

Еще одна быстрая аналогия: возвращать 404 для «результат не найден» - это все равно, что выдавать исключение DatabaseConnectionException, если запрос SQL не дал результатов. Он может выполнить работу, но существует множество возможных технических причин, которые вызывают одно и то же исключение, которое затем будет ошибочно принято за действительный результат.

Йенс Вурм
источник
30
Технические причины «не найдены» также известны как ошибки сервера. Это должно быть в 500-х. В частности: «Служба не может быть найдена»503 Service Unavailable .
Крис Пфол
43
Спрашивающий также спрашивал о конкретном ресурсе: один пользователь (не /users маршрут, а /users/9, например, «пользователь, известный как # 9»), поэтому сравнение с «пустым набором результатов» не имеет смысла. 404 означает, что объект не существует.
Крис Пфол
29
404 просто указывает, что запрошенный ресурс (в данном случае пользователь номер 9) не был найден. Это не имеет никакого отношения к тому, был ли запущен код приложения, оно не имеет никакого отношения к тому, ответил или нет бэкэнд-приложение. Вопрос в том, что такое веб-сервер, в вопросе не упоминалось обратное проксирование.
Крис Пфол
29
Рассуждения в этом ответе ужасно неверны.
Курт Шпиндлер
21
404: клиент смог связаться с данным сервером, но сервер не смог найти то, что было запрошено. Буквально: запрос получен, он был в порядке и правильно отформатирован (неверный запрос 400), он был аутентифицирован или общедоступен (неавторизован 401 / запрещен 403), платеж не требуется (требуется платеж 402), метод запроса был в порядке (метод не разрешен 405 ), запрос может быть удовлетворен (не принято 406). 200 Ok следует использовать, когда пользователь получает ресурс. Пусто не ресурс. Диапазон 400 - для ошибок клиента. Диапазон 500 - для ошибок сервера. Короче говоря: Ваш вывод отключен.
Дерк-янв
62

Сначала я думал, что 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, пользователь Кайл не доступен ресурс поэтому 404 все еще применяется. Это не поисковый запрос, это прямая ссылка по динамическому URL , так что 404 это так.

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

Юстус Ромейн
источник
9
Бросив свой вес за этот стиль для REST API. Ни один клиент не должен запрашивать / users / kyle, если только ему не сказали, что ресурс будет существовать через вызов либо / users, либо / users? Name = kyle
Гари Баркер
@GaryBarker Но так как это «пользовательский ввод» в некотором роде, API все равно должен обрабатывать его правильно. Хотя вы должны запретить 404 в ВАШЕМ клиенте, вы не можете быть уверены, что он действительно был проверен в первую очередь. Разработка API должна выполняться без учета точной реализации вашего клиента, особенно с точки зрения проверенного пользовательского ввода.
RicoBrassers
Это ответ, с которым я больше всего согласен. Прекрасный пример того, как я хочу, чтобы API работали. @ GaryBarker комментарий тоже идеально. Это ошибка, когда вы ищете что-то по идентификатору, и это не существует. Вы должны знать, что идентификатор существует до совершения звонка. Главным образом потому, что получение некоторого «успешного» пустого ответа просто вызывает ошибку в дальнейшем, вероятно, для некоторых «не может прочитать имя свойства undefined» при выполнении user.name или чего-то еще.
Джейми Twells
Как насчет комбинации двух. Предполагая, что у пользователей есть друзья. / пользователи / Kyle / друзья? имя = Фред. Кайл не существует, так будет ли этот ответ 404? Или это будет 200, потому что нас не интересует Кайл, мы заботимся только о поиске его друзей по имени Фред?
JSextonn
ИМО, которая выдаст 404, поскольку это неверный запрос: Кайла не существует, поэтому поиск его друзей также невозможен.
Юстус Ромейн
23

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

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

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

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

j0057
источник
1
Похоже, вы предпочитаете программировать против API, используя более абстрактную форму, называемую RPC. Вместо того, чтобы обращаться к ресурсам, внимательно следуя глаголам, и URL, основанный на ресурсах, например customers/1/addressbook, способ RPC состоит в том, чтобы вызывать конечную точку как GetCustomerAddressBookи либо получать данные, либо, по существу, нулевые значения, и не беспокоиться о сложностях HTTP. Есть плюсы и минусы для обоих.
Маффин Ман
2
@ Маффин, я не уверен, как ты можешь притворяться, что знаю, предпочитаю ли я REST или RPC, и почему это имеет отношение к обсуждению того, какой код состояния возвращать в запрос HTTP GET.
j0057
У меня были некоторые ужасные проблемы с кэшированием при использовании 204. Chrome будет странно относиться к запросу и не будет ничего показывать в сети и кэширует предыдущий результат. Даже со всеми заголовками без кеша в мире. Я согласен с этим ответом, 200 кажется лучшим с пустым массивом / объектом, переданным пользователю.
Джек
22

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

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

Максимум
источник
14

Согласно сообщению w3 ,

200 ОК

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

202 Принято

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

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

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

ошибка 400, неверный запрос

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

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

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

404 Не Найдено

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

JustCode
источник
Сообщение w3 о кодах состояния HTTP. HTTP не идентичен REST. REST в основном, но не обязательно, использует HTTP в качестве транспортного протокола. 404 - это код ошибки транспорта HTTP. Если REST будет таким же, как HTTP, не должен ли он называться HTTP?
anneb
1
@anneb Как вы сказали, REST использует HTTP, поэтому этот ответ имеет смысл. REST - это не HTTP, REST - это не протокол. REST не обязательно должен быть идентичным (или таким же, как HTTP), чтобы этот ответ не имел смысла.
Корай Тугай
@Koray Tugay: поиск в Google также использует http, поэтому в соответствии с этим ответом поиск Google должен ответить http 404, если ничего не соответствует запросу?
anneb
@anneb Поиском Google вы упомянули приложение RESTful? Я так не думаю .. Отсюда и ответ будет нет. Вернемся к исходному вопросу и этому ответу вместо того, чтобы упасть в кроличью нору. Если Google Search однажды создаст RESTful API (или, возможно, он уже есть, я не знаю), он может вернуться, 204 No Contentкогда не найдет результатов. Нет 404, у вас есть результат, но он не имеет никакого содержания ..
Корай Тугай
13

Подводя итог или упростить,

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

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

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

Ашиш Сингх
источник
12

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

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

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

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

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

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

Bluebox
источник
9

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

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

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

1.- ресурс это: /users

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

так:

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

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

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

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

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

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

rodfraga
источник
8

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

  • В случае параметров пути этот параметр является частью пути ресурса. В случае /users/9, ответ должен быть, 404потому что этот ресурс не был найден. /users/9является ресурсом, и результат унарный, или ошибка, он не существует. Это не монада.
  • В случае параметров запроса этот параметр не является частью пути к ресурсу. В случае /users?id=9, ответ должен быть, 204потому что ресурс /usersбыл найден, но он не мог возвратить никакие данные. Ресурс /usersсуществует, и результат n-арный, он существует, даже если он пуст. Если idуникален, это является монадой.

Использовать ли параметры пути или параметры запроса, зависит от варианта использования. Я предпочитаю параметры пути для обязательных, нормативных или идентифицирующих аргументов и параметры запроса для необязательных, ненормативных или атрибутивных аргументов (таких как разбиение на страницы, локаль сопоставления и прочее). В REST API я бы использовал /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вместо этого, открывается совершенно другая банка червей.

Кристиан Худжер
источник
5

Twitter использует 404 с пользовательским сообщением об ошибке типа «Данные не найдены».

Ссылка: https://developer.twitter.com/en/docs/basics/response-codes.html

сойка
источник
2
Microsoft Azure также использует 404, но пользовательское сообщение об ошибке невозможно при ответе на запросы HEAD. docs.microsoft.com/en-us/rest/api/resources/resources/…
Майк
3

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

刘武豪
источник
Вы не должны возвращать 404, если у вас есть ошибка бэкэнда.
appalling22
3

Я бы сказал, ни то, ни другое не подходит. Как уже было сказано - например, @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если мы знаем, что оно перешло в Голливуд
  • if return/testсчитается поисковой или фильтр-подобной операцией: если набор результатов пуст, вернуть пустой набор в запрошенном типе и статус REST:EMPTY; набор результатов в запрашиваемом типе и статусREST:SUCCESS
  • if return/testне является операцией, распознанной с помощью SERVICE: return, 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 может предоставить из своей собственной области: а именно, была ли найдена служба для обработки запроса или нет.

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

dariok
источник
2

Согласно 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).

Таким образом, в моем понимании код состояния 404 не должен использоваться при успешном GET-запросе с пустым результатом. (Пример: список без результата для определенного фильтра)

Филипе Мойзес
источник
2

Такие вещи могут быть субъективными, и с обеих сторон есть несколько интересных и разных весомых аргументов. Однако [по моему мнению] возвращать 404 за отсутствующие данные не правильно . Вот упрощенное описание, чтобы прояснить это:

  • Запрос: Могу ли я получить некоторые данные, пожалуйста?
  • Ресурс (конечная точка API): я получу этот запрос для вас, здесь [отправляет ответ потенциальных данных]

Ничего не сломалось, конечная точка была найдена, а таблица и столбцы были найдены, поэтому БД запросила и данные были «успешно» возвращены!

Теперь - независимо от того, есть ли у этого «успешного ответа» данные или нет, не имеет значения, вы запросили ответ «потенциальных» данных, и этот ответ с «потенциальными» данными был выполнен. Пустые, пустые и т. Д. Являются действительными данными.

200 означает, что любой запрос, который мы сделали, был успешным. Я запрашиваю данные, ничто не пошло не так с HTTP / REST, и когда данные (хотя и пустые) были возвращены, мой «запрос данных» был успешным.

Верните 200 и позвольте запрашивающей стороне иметь дело с пустыми данными, поскольку каждый конкретный сценарий гарантирует это!

Рассмотрим этот пример:

  • Запрос: запрос "нарушения" таблицы с идентификатором пользователя 1234
  • Ресурс (конечная точка API): возвращает ответ, но данные пусты

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

У вас нет нарушений, есть черничный кекс!

Если вы считаете это 404, что вы заявляете? Нарушения пользователя не могут быть найдены? Теперь, грамматически это правильно, но это просто неправильно в мире REST, где успех или неудача связаны с запросом. Данные о "нарушении" для этого пользователя могут быть успешно найдены, нарушений нет - действительное число, представляющее действительное состояние.


[Дерзкая записка ..]

В своем названии вы подсознательно соглашаетесь с тем, что 200 является правильным ответом:

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


Вот некоторые вещи, которые следует учитывать при выборе кода состояния, независимо от субъективности и хитрости выбора:

  1. Согласованность . Если вы используете 404 для «нет данных», используйте его каждый раз, когда ответ не возвращает никаких данных.
  2. Не используйте один и тот же статус для более чем одного значения . Если вы вернете 404, когда ресурс не найден (например, конечная точка API не существует и т. Д.), То не также используйте его, если данные не возвращаются. Это только делает борьбу с ответами болью.
  3. Тщательно продумайте контекст . Что такое «запрос»? Что вы говорите, что пытаетесь достичь?
Джеймс
источник
1

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

Заходи
источник
1

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

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

Akshat
источник
2
«ожидается, что клиент никогда не сделает запрос» - и что если этот пользователь будет создан позже, ваш ответ предполагает, что вы можете гарантировать, что этот пользователь никогда не будет существовать, это очень смелое предположение и, скорее всего, неправильно
Holly
Что сказала Холли. Чтобы добавить к ее пункту: даже в случае, если пользователь существовал и был удален, 410 неправильно, потому что, что, если пользователь будет удален? (Какой особый случай создается позже).
Кристиан Худжер
потому что 410 должен быть постоянной ситуацией. restapitutorial.com/httpstatuscodes.html
Akostha
1

Грустно, что что-то такое простое и четкое стало «основанным на мнении» в этой теме.

HTTP-сервер знает только о «сущностях», которые являются абстракцией для любого контента, будь то статическая веб-страница, список результатов поиска, список других сущностей, описание чего-либо в формате json, файл мультимедиа и т. Д. И т. Д. И т. Д.

Предполагается, что каждый такой объект может быть идентифицирован по уникальному URL, например

  • / пользователь / 9 - один объект: идентификатор пользователя = 9
  • / users - один объект: СПИСОК всех пользователей
  • /media/x.mp3 - один объект: медиа-файл с именем x.mp3
  • / search - единая сущность: динамический CONTENT, основанный на параметрах запроса

Если сервер находит ресурс по заданному URL-адресу, не имеет значения, каково его содержимое - 2G данных, ноль, {}, [] - до тех пор, пока он существует, он будет равен 200. Но если такой объект является серверу неизвестно, ожидается 404 "Not Found".

Одна путаница, кажется, от разработчиков, которые думают, что если приложение имеет обработчик для определенной формы пути, это не должно быть ошибкой. В глазах протокола HTTP не имеет значения, что произошло во внутренних элементах сервера (т. Е. Ответил ли маршрутизатор по умолчанию или обработчик для определенной формы пути), если на сервере нет соответствующей сущности для запрошенный URL (который запрашивал файл MP3, веб-страницу, пользовательский объект и т. д.), который возвращал бы допустимое содержимое (пустое или иное), он должен быть 404 (или 410 и т. д.).

Другая путаница, кажется, связана с «нет данных» и «нет сущности». Первое касается содержания сущности, а второе - ее существования.

Пример 1:

  • Нет данных: / users возвращает 200 OK, body: [], потому что никто еще не зарегистрирован
  • Нет объекта: / users возвращает 404, потому что нет пути / users

Пример 2:

  • Нет данных: / user / 9 возвращает return 200 OK, body: {}, потому что ID пользователя = 9 никогда не вводил свои личные данные
  • Нет объекта: / user / 9 возвращает 404, потому что нет идентификатора пользователя = 9

Пример 3:

  • Нет данных: / search? Name = Джо возвращает 200 OK [], потому что в БД нет Джо
  • Нет объекта: / search? Name = Джо возвращает 404, потому что нет пути / поиска
Дарко Максимович
источник
0

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

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

тёмная энергия
источник
0

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

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

Все остальные существующие статусы не применимы по той или иной причине.

Я видел эту тему, обсуждаемую много раз в нескольких местах. Для меня совершенно очевидно, что для устранения путаницы вокруг темы необходим специальный статус успеха. Что-то вроде « 209 - Нет ресурсов для отображения».

Это будет статус 2xx, потому что не обнаружение идентификатора не должно считаться ошибкой клиента (если клиенты знают все, что находится в БД сервера, им не нужно ничего запрашивать на сервере, не так ли?). Этот специальный статус решит все проблемы, обсуждаемые с использованием других статусов.

Единственный вопрос: как мне заставить RFC принять это как стандарт?

Умберто Бар
источник