Правильно ли возвращать 404, когда ресурс REST не найден?
предположим, у меня есть простой ресурс отдыха Джерси следующим образом:
@Path("/foos")
public class MyRestlet
extends BaseRestlet
{
@GET
@Path("/{fooId}")
@Produces(MediaType.APPLICATION_XML)
public Response getFoo(@PathParam("fooId") final String fooId)
throws IOException, ParseException
{
final Foo foo = fooService.getFoo(fooId);
if (foo != null)
{
return Response.status(Response.Status.OK).entity(foo).build();
}
else
{
return Response.status(Response.Status.NOT_FOUND).build();
}
}
}
основываясь на приведенном выше коде, правильно ли возвращать NOT_FOUND
статус (404
), или я должен вернуться 204
, или какой-то другой более подходящий код?
заранее большое спасибо!
3 ответов
ответ 404 в этом случае довольно типичен и прост для пользователей API.
одна проблема заключается в том, что клиенту трудно сказать, получили ли они 404 из-за того, что конкретный объект не найден, или из-за структурной проблемы в URI. В вашем примере, /foos/5
может возвращать 404, потому что foo с id=5 не существует. Однако,/food/1
вернет 404, даже если foo с (поскольку foos
- это неправильно). Другими словами, 404 означает либо плохо сконструированный URI или ссылка на несуществующий ресурс.
другая проблема возникает, когда у вас есть URI, который ссылается на несколько ресурсов. С помощью простого ответа 404 клиент понятия не имеет, какой из указанных ресурсов не найден.
обе эти проблемы могут быть частично смягчены путем возврата дополнительной информации в теле ответа, чтобы абонент точно знал, что не было найдено.
Да, довольно часто возвращается 404 для ресурса, который не найден. Так же, как веб-страница, когда она не найдена, вы получаете 404. Это не просто отдых, а стандарт HTTP.
каждый ресурс должен иметь URL-адрес. URL-адреса не должны быть статическими, они могут быть templated. Таким образом, возможно, что фактический запрошенный URL-адрес не имеет ресурса. Это обязанность сервера, чтобы сломать URL из шаблона, чтобы искать ресурс. Если они ресурс не существует, тогда это "Не Найден"
404 Не Найдена
сервер не нашел ничего, что соответствовало бы запросу-URI. Не указывается, является ли это состояние временным или постоянным. Код состояния 410 (Gone) должен использоваться, если сервер знает через какой-либо внутренне настраиваемый механизм, что старый ресурс постоянно недоступен и не имеет адрес пересылки. Этот код состояния обычно используется, когда сервер не хочет точно указать, почему запрос был отклонен, или когда никакой другой ответ не применим.
вот для 204
204-Нет Содержимого
сервер выполнил запрос, но не должен возвращать тело сущности и может захотеть вернуть обновленную метаинформацию. Ответ может включать новые или обновленные метаинформация в виде заголовков сущностей, которые при наличии должны быть связаны с запрашиваемым вариантом.
если клиент является агентом пользователя, он не должен изменять свое представление документа от того, что вызвало запрос для отправки. Этот ответ в первую очередь предназначен для ввода действий без изменения активного представления документа агента пользователя, хотя к документу, находящемуся в данный момент в пользователе, должна применяться любая новая или обновленная метаинформация активный вид агента.
ответ 204 не должен содержать тело сообщения, и, таким образом, всегда завершается первой пустой строкой после полей заголовка.
обычно 204 будет использоваться, когда представление было обновлено или создано, и нет необходимости отправлять тело ответа обратно. В случае публикации вы можете отправить только местоположение вновь созданного ресурса. Что-то вроде
@POST
@Path("/something")
@Consumes(...)
public Response createBuzz(Domain domain, @Context UriInfo uriInfo) {
int domainId = // create domain and get created id
UriBuilder builder = uriInfo.getAbsolutePathBuilder();
builder.path(Integer.toString(domainId)); // concatenate the id.
return Response.created(builder.build()).build();
}
на created(URI)
Пошлет назад ответ с вновь созданным URI в Location
заголовок.
добавление к первой части. Вам просто нужно иметь в виду, что каждый запрос от клиента-это запрос на доступ к ресурсу, будь то просто получить его или обновить с помощью PUT. А ресурсом может быть что угодно на сервере. Если ресурс не существует, то общим ответом будет сказать клиенту, что мы не можем найти этот ресурс.
чтобы расширить свой пример. Скажем FooService
accsses БД. Каждую строку в базе данных можно считать ресурсом. И каждая из этих строк (ресурсов) имеет уникальный URL-адрес, как foo/db/1
может найти строку с первичным ключом 1. Если ID не может быть найден, то ресурс is "Не Найден"
A 4XX
код ошибки означает ошибку со стороны клиента.
Когда вы запрашиваете статический ресурс в виде изображения или html-страницы, возвращая 404
ответ имеет смысл, так как :
код ответа на ошибку клиента HTTP 404 не найден указывает, что сервер не может найти запрашиваемый ресурс. Ссылки, которые ведут на 404 страницы часто называют сломанными или мертвыми ссылками и могут быть предметом ссылки гниль.
как вы предоставите для клиентов некоторых методов REST вы полагаетесь на методы HTTP, но не должны рассматривать службы REST как простые ресурсы.
Для клиентов ответ на ошибку в методе REST часто обрабатывается близко к ошибкам других процессов.
например, чтобы поймать ошибки во время вызовов REST или где-то еще, клиенты могут использовать catchError()
of RxJS.
мы могли бы написать код (в TypeScript/Angular 2 для примера кода) таким образом, чтобы делегировать обработка ошибки в функцию:
return this.http
.get<Foo>("/api/foos")
.pipe(
catchError(this.handleError)
)
.map(foo => {...})
проблема в том, что любая ошибка HTTP (5XX или 4XXX) завершится в catchError()
обратный.
Это может действительно сделать ответы REST API вводящими в заблуждение для клиентов.
если мы сделаем параллель с языком программирования, мы могли бы рассмотреть 5XX / 4XX как поток исключений.
Как правило, мы не исключение, только потому, что данные не найдены, мы бросаем его, поскольку данные не найдены и что эти данные будут иметь найден.
Для REST API мы должны следовать той же логике.
если предприятие мая не найдено, возвращается OK
в этих двух случаях совершенно нормально :
@GET
@Path("/{fooId}")
@Produces(MediaType.APPLICATION_XML)
public Response getFoo(@PathParam("fooId") final String fooId)
throws IOException, ParseException {
final Foo foo = fooService.getFoo(fooId);
if (foo != null){
return Response.status(Response.Status.OK).entity(foo).build();
}
return Response.status(Response.Status.OK).build();
}
клиент может так обрабатывать результат в соответствии с результатом присутствует или отсутствует.
Я не думаю, что возвращение 204
приносит какую-либо полезную ценность.
С http 204
документация гласит :
клиенту не нужно уходить со своей текущей страницы.
но запрос ресурса REST и, в частности, методом GET не означает, что клиент завершает рабочий процесс (что имеет больше смысла с методами POST/PUT).
документ добавляет также :
общим случаем использования является возврат 204 в результате запроса PUT, обновление ресурса без изменения текущего содержимого страницы отображается для пользователя.
мы действительно не в этом дело.
некоторые конкретные HTTP-коды для классического просмотра matche точно с кодами возврата REST API (201, 202, 401 и т. д.)...) но это не всегда так.
Поэтому для этих случаев, вместо того, чтобы скручивать оригинальные коды, я бы предпочел сохранить их простыми, используя более общие коды:200
, 400
.