#rest #http
#rest #http
Вопрос:
В последнее время я начал добавлять коды состояния к своим ответам вместо того, чтобы возвращать их напрямую.
Давайте предположим, /person/1
возвращает пользователя с идентификатором 1 из базы данных. Если пользователь не существует, должен ли я вернуть статус 404? Как я должен различать, если конечная точка не существует на сервере или ресурс не существует?
Теперь давайте предположим, что у меня есть конечная точка POST для вставки пользователей. Что, если эта конечная точка проверяет, правильно ли сформировано электронное письмо, и я возвращаю 400? Как я должен знать, был ли запрос сформирован неправильно и не был перенаправлен ни на какие сервлеты, или он действительно достиг сервлета, который решил, что электронное письмо неправильно сформировано?
Является ли хорошей практикой всегда возвращать ответ 200 OK от всех моих сервлетов, указывающий, что приложение выполнило свою работу независимо от результата, и записывать статус в поле json status
или это излишество и антишаблон?
У меня нет большого опыта или знаний о HTTP-серверах, поэтому я не уверен, что правильно это объясняю (или использую), поэтому я приношу извинения за широкие описания.
Ответ №1:
Давайте предположим, что /person/1 возвращает пользователя с идентификатором 1 из базы данных. Если пользователь не существует, должен ли я вернуть статус 404? Как я должен различать, если конечная точка не существует на сервере или ресурс не существует?
Для клиента не имеет значения, не существовал ли ресурс или конечная точка. Все, что сервер сообщает, это то, что для данного URI нет доступного представления.
Как уже упоминалось inf3rno, клиент обычно получает все URI, которые понадобятся клиенту, от сервера непосредственно в ответе. При размещении закладок или включении ссылок на какой-либо внешний ресурс определенные ссылки могут со временем стать недействительными, и как таковой 404 Not Found
ответ просто информирует клиента о том, что для данного URI недоступно представление.
Клиент, как правило, также не заинтересован во внутренних компонентах API, а просто в отправке или получении данных, с которыми он может работать.
К сожалению, у многих пользователей есть еще одно заблуждение, заключающееся в том, что они уже используют определенные ресурсы для возврата определенных типов. Такие типы могут привести к сбоям на стороне клиента, если ожидаемый формат представления когда-либо изменится. В дополнение к этому сама структура URI, включая любой путь, матрицу и параметры запроса, не должна использоваться для вывода какой-либо логической структуры API, его открытых конечных точек или логической структуры ресурсов из других ресурсов этого API. URI в целом является указателем на ресурс. Ресурс может содержать десятки ссылок, указывающих на него. Вы могли бы рассматривать URI как ключ кэша для возвращаемых представлений, которые при последовательных вызовах дополнительно обслуживаются кэшем вместо фактического сервера. На самом деле это одно из ограничений, налагаемых REST и широко используемых в Интернете.
Теперь давайте предположим, что у меня есть конечная точка POST для вставки пользователей. Что, если эта конечная точка проверяет, правильно ли сформировано электронное письмо, и я возвращаю 400? Как я должен знать, был ли запрос сформирован неправильно и не был перенаправлен ни на какие сервлеты, или он действительно достиг сервлета, который решил, что электронное письмо неправильно сформировано?
RFC 7231 определяет POST
как универсальный инструмент, который следует использовать, если другие методы не подходят для поставленной задачи. В нем явно указано, что полезная нагрузка, предоставляемая этим методом, будет processed according to the resource's own specific semantics
. Итак, если вам нужно подтвердить адрес электронной почты пользователя перед его сохранением или перед запуском вычисления, фонового процесса или чего-то еще, отлично, сделайте это 🙂 Даже PUT , который, как часто говорят, только заменяет текущее представление на указанное в запросе, не только разрешен, но и поощряется выполнять проверки относительно любых ограничений, которые сервер имеет для целевого ресурса, и, следовательно, он должен отказаться от полезных нагрузок, которые не соответствуют его ожиданиям.
Суть здесь в том, что сервер должен всегда предоставлять клиенту как можно больше информации, чтобы позволить клиенту определить, что делать дальше. Представьте веб-приложение, к которому вы получаете доступ через свой браузер. Если вы получаете 400 Bad Request
, браузер обычно сообщает, что серверу не понравилось в вашем запросе, т.е. неполный синтаксис или отсутствующее значение обязательного поля. То же самое справедливо и для REST API, поскольку они в основном являются просто обобщением модели взаимодействия, используемой в Интернете. Таким образом, те же концепции, которые применимы к Сети, применимы и к REST 🙂
Таким образом, каждый код состояния HTTP имеет свою собственную семантику и должен помочь клиенту определить, что ему следует делать дальше. 400 Bad Request
Т.е. указывает, что сервер либо не может, либо не будет обрабатывать запрос из-за чего-то, что сервер считает ошибкой на основе клиента, и клиент должен исправить эту ошибку и повторно отправить запрос.
405 Method Not Allowed
С другой стороны, указывает, что клиент использовал HTTP-метод, не поддерживаемый целевой конечной точкой. Ответ с ошибкой не только указывает это клиенту, но также указывает, какие методы разрешены на целевой конечной точке в Alllow
заголовке ответа.
Каждый из кодов состояния HTTP, указанных в RFC 7231, имеет свою собственную семантику, и, вероятно, целесообразно хотя бы бегло просмотреть их. Вы также можете просмотреть все доступные коды состояния в IANA, которая предоставляет ссылки на спецификацию, описывающую эти коды состояния.
Является ли хорошей практикой всегда возвращать ответ 200 OK от всех моих сервлетов, указывающий, что приложение выполнило свою работу независимо от результата, и записывать статус в поле json status или это излишество и антишаблон?
Как и коды ошибок, коды успеха (в диапазоне 200) также имеют свою собственную семантику. Если новый ресурс создается в результате обработки запроса (через PUT
или POST
), клиент должен быть уведомлен с помощью 201 Created
ответа о статусе, что furthremore содержит HTTP Location
заголовок, содержащий URI, ориентированный на вновь созданный ресурс.
Если серверу может потребоваться некоторое время для вычисления ответа, вероятно, целесообразно вернуть 202 Accepted
ответ, чтобы проинформировать клиента об ожидающем запросе. Клиент может позже выполнить запрос либо по истечении некоторого порогового периода, либо после получения уведомления от сервера с помощью механизмов обратного вызова, таких как уведомление по электронной почте или тому подобное. Из-за ограничений немецкого законодательства, т.е. немецкие компании должны поддерживать архивы своих сообщений, которыми обмениваются через EDI. Мы, как поставщик EDI, предлагаем нашим клиентам выполнить архивирование их обмененных сообщений посредством запуска одной из наших конечных точек HTTP. В зависимости от количества сообщений, которыми обменивается эта компания, и выбранного периода времени, для которого должен быть сгенерирован архив, этот процесс может занять некоторое время (точнее, пару часов), и вместо того, чтобы позволить клиенту ждать этот период, мы просто возвращаемся 202 Accepted
и запускаем процесс архивирования с обратной стороны. В зависимости от конфигурации они либо запрашивают готовый архив, получают информацию о конечном результате, либо напрямую отправляют архив по электронной почте, если файл не слишком большой.
204 No Content
также весьма полезно, если клиент выполняет обновление ресурса. Как PUT
обычно определяется как замена текущего представления на то, которое предоставлено в полезной нагрузке, после получения 204 No Content
ответа клиент знает, что сервер применил обновление, и текущее представление действительно похоже на запрошенное клиентом. Таким образом, серверу не нужно дополнительно информировать клиента о том, как выглядит текущее представление, поскольку клиент уже знает, как оно должно выглядеть. Однако, в случае, если серверу пришлось преобразовать полезную нагрузку в другое представление, что может привести к другому результату, вероятно, полезно сообщить клиенту о новом состоянии ресурса в 200 OK
ответе, включающем представление результата процесса обновления.
Возврат 200 OK
при сбое, включающий полезную нагрузку JSON с полями, указывающими на ошибку, наверняка является плохим способом продолжения. Это не только дает клиентам неверную подсказку, но и ответ может быть кэширован посредниками и возвращен другим клиентам, запрашивающим то же самое, даже если сбой может быть только временного характера (сбой базы данных или тому подобное). В дополнение к этому такая полезная нагрузка JSON, вероятно, использующая нестандартизированный формат и, следовательно, требующая внеполосных знаний для фактической обработки сообщения. В то время как мы, люди, вполне способны понять, что происходит, компьютеры сами по себе еще не настолько умны.
Я надеюсь, вы можете видеть, что HTTP предлагает много семантики в отношении того, когда использовать какой метод или код ответа. Они существуют не просто так, и поэтому их также следует использовать при благоприятных обстоятельствах.
Комментарии:
1. ВАУ, это было подробное объяснение : D Я уже написал довольно много приложений REST, но мои коллеги время от времени спрашивали меня что-то вроде: 404 был вызван тем, что они отправили неправильный идентификатор или нацелились на неправильную конечную точку (хотя мы используем Swagger : P). Ваш ответ, несомненно, проливает больше света на проблему. На самом деле я думал, что возврат 200 был плохой идеей, но это было то, что мы обсуждали, и поскольку сейчас мы начинаем новый проект, я хотел это изменить. Спасибо за все аргументы, которые я могу привести им сейчас, особенно за тот, который касается кэша: D
Ответ №2:
В запросе GET 404
статус — это просто код ответа. Вы должны предоставить сообщение об ошибке в теле ответа в случае, если запись не найдена для предоставленного идентификатора.
Для запроса POST вы можете вернуть 400
код ошибки с указанием в теле, какие поля отсутствуют / проверка не выполняется.
Для URL не найден, Пользователь всегда будет получать 404
код ошибки.
Для успешного запроса GET или POST вы можете вернуть ответ со 200
статусом
Ответ №3:
Как я должен различать, если конечная точка не существует на сервере или ресурс не существует?
Конечной точкой в данном случае является IRI (URI) веб-ресурса. Если конечная точка не существует, то есть большая вероятность, что веб-ресурс также не существует. Это маловероятный сценарий, поскольку вы получили свои URI с сервера (HATEOAS), но это может произойти, если что-то изменится между двумя запросами, например, изменится шаблон URI или кто-то удалит ресурс. Во всех этих случаях 404 является прекрасным кодом состояния HTTP. Вы можете уточнить в сообщении об ошибке или использовать дополнительный код ошибки, но для меня это не имеет смысла, потому что изменение шаблона URI — редкое событие. Однако это сделало бы клиент более гибким, поскольку он мог бы очистить кэш и повторить попытку с новой ссылкой.