Должен ли я вернуть ответ 204 или 404, если ресурс не найден?

15

Я занимаюсь разработкой простого сервиса RESTful для турниров и расписаний. Когда турнир создается с помощью запроса POST, содержащего тело JSON, турнир вставляется в элемент BiMap, объявленный в реализации DAO следующим образом:

private BiMap<String, Tournament> tournaments = Maps.synchronizedBiMap(HashBiMap.create());

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

GET http://localhost:8080/eventscheduler/c15268ce-474a-49bd-a623-b0b865386f39

Но что, если турнир с таким идентификатором не найден? Пока я возвращаю 204 ответа. Ну, Джерси делает это для меня, когда возвращается nullодним из методов. Это метод, который соответствует маршруту выше:

@Path("/{id}")
@GET
@Produces(MediaType.APPLICATION_JSON)
public Tournament getTournament(@PathParam("id") String id) {
    Optional<Tournament> optTournament = tournamentDao.getTournament(id);
    if (optTournament.isPresent())
        return optTournament.get();
    return null;
}

Мой вопрос: нормально ли возвращать 204: No Contentответ, или это должен быть 404ответ, поскольку ресурс не был найден?

Если я должен изменить его на 404, очевидный вопрос: я должен изменить подпись метода, верно? Так как теперь турнир (типа Tournament) не может быть возвращен, метод должен выглядеть иначе. Должен ли я использовать Responseтип в качестве типа возврата вместо?

dabadaba
источник

Ответы:

32

HTTP 204означает, что что-то было найдено, но оно пустое. Например, представьте, что вы обслуживаете файлы журнала через HTTP с такими запросами, как http://example.com/logs/[date-goes-here] . 18 мая 2015 года:

  • http://example.com/logs/2015-05-19 будет возвращаться HTTP 404, что означает, что нет никаких журналов, потому что, ну, трудно записать будущее.

  • Однако http://example.com/logs/2015-05-18 будет возвращаться либо HTTP 200с записями журнала в содержании ответа, либо, HTTP 204если файл журнала был создан, но для этого еще нет записанных журналов. свидание.

Если вы предоставляете nullплатформе ответ на запрос, предполагается, что вы нашли запись, и поэтому эта запись пуста HTTP 204. Вместо этого вы должны throw new NotFoundException();указать платформе, что запись не существует, чтобы она генерировала HTTP 404.

Если я должен изменить его на 404, очевидный вопрос: я должен изменить подпись метода, верно?

Нет, ты не Это хорошая вещь о throw new NotFoundException();. Он будет работать независимо от того, каков реальный тип возврата вашего метода.

Арсений Мурзенко
источник
5
Обратите особое внимание на RFC 2616 . 204 ответа соответствуют спецификации, только если вы полностью опускаете тело сообщения. В какой-то степени смысл ответа 204 года заключается в том, чтобы сказать: «Нет, это не случайность, что я не вернул никакого контента». Развернем пример MainMa: Если средство поиска журналов выплевывает текстовые файлы (например, тонкая оболочка вокруг файлов журналов, которая просто выдает файл журнала как есть), то 204 подойдет для пустого файла журнала. Если ответ был пустым объектом JSON (например, {content: ''}), ответ 204 был бы неуместным.
Брайан
« потому что, ну, трудно записать будущее. » - этот бит зависит от произвольной даты; почему бы не сделать это чем-то, что не требует от читателя притворяться, что это не сегодня? Может 2015-02-29быть, лучше использовать, потому что это дата, которой вообще не существует?
Фонд Моника иск
3

Вы должны вернуть 404. Вы можете сделать это, бросив NotFoundException ( https://jersey.java.net/apidocs/2.6/jersey/javax/ws/rs/NotFoundException.html ).

Также, пожалуйста, посмотрите на этот вопрос SO, если вам нужно контролировать возвращаемый тип контента /programming/23858488/how-i-return-http-404-json-xml-response-in-jax-rs- Джерси-на-кот

Chamindu
источник
1

Ваш запрос GET http://localhost:8080/eventscheduler/c15268ce-474a-49bd-a623-b0b865386f39.

Если http://localhost:8080/eventscheduler/не существует как конечная точка, вы должны вернуть 404. Вы пытаетесь получить доступ к ресурсу ( /eventscheduler/), который не существует. Это будет указывать клиенту, что сервер существует localhost:8080, но в eventschedulerконечной точке ничего нет .

Если http://localhost:8080/eventscheduler/существует в качестве конечной точки, но требуемые ресурсы недоступны, подходит ошибка 5xx. Хороший пример этого может быть, если база данных находится в автономном режиме, где вы можете вернуть 503. Конечно, вы можете просто захотеть вернуть общую ошибку 500 вместо конкретного экземпляра.

Если http://localhost:8080/eventscheduler/существует, но вещь, представленная как c15268ce-474a-49bd-a623-b0b865386f39, не существует, я бы вернул 200 с телом, указывающим детали. Конечная точка существует, сделанный запрос был полностью действительным и мог быть обработан, но совпадений не было.

Если запрос вашего клиента к конечной точке был недействительным, вы бы посмотрели на другие ошибки 4xx. Вы можете указать, что клиент не авторизован для доступа к конечной точке или элементам, запрошенным с помощью 401 или 403, или может использовать 400, чтобы указать, что запрос недействителен. С любым из них дополнительная информация может быть предоставлена ​​в теле ответа.

Томас Оуэнс
источник
Нет необходимости различать конечную точку и ресурс. Если URI не соответствует каким-либо ресурсам, по какой-либо причине сервер должен вернуть 404.
bdsl
Посмотрите код ответа на этом сайте, чтобы узнать, как сайт поступает правильно. Это веб-сайт, а не API, но применяется та же спецификация http. softwareengineering.stackexchange.com/questions/266183385
BDSL
@bdsl Я могу вам сказать, что это абсолютно неправильно. Например, я взаимодействую с пользовательским сервисом, который может вернуть профиль пользователя. Допустим, эта конечная точка используется /userи используется как /user?email=test@example.com. Как потребитель API, я хочу знать, если /userпо какой-то причине на сервере не существует (возможно, он был добавлен в v2 API, а сервер - в v1, или он был переименован в v3), или если пользователь с электронной почтой test@example.comне существует Первый - 404, второй - 200 с телом, которое не указывает ни одного пользователя с таким адресом электронной почты.
Томас Оуэнс
@bdsl Это хорошо, но это не значит, что это правильно или лучше. Я также не думаю, что вы можете сравнить веб-сайт, предназначенный для взаимодействия с человеком через веб-браузер, и API, предназначенный для использования в программной системе.
Томас Оуэнс
1
Этот вопрос обсуждается далее в youtube.com/watch?v=nSKp2StlS6s
bdsl