REST API 404: плохой URI или отсутствующий ресурс?

Я создаю REST API, но я столкнулся с проблемой.

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

однако для меня это добавляет ненужную двусмысленность. HTTP 404 более традиционно ассоциируется с плохим URI. Таким образом, мы говорим "либо вы попали в нужное место, но этой конкретной записи не существует,или нет такого места на Инете! Я действительно не уверен, какой именно..."

рассмотрим следующий URI:

http://mywebsite/api/user/13

Если я получу 404 назад, это потому, что пользователь 13 не существует? Или это потому, что мой URL должны было:

http://mywebsite/restapi/user/13

в прошлом я только что вернул нулевой результат с HTTP 200 OK код ответа, если запись не существует. Это просто и, на мой взгляд, очень чисто, даже если это не обязательно принятая практика. Но есть ли лучший способ этого?

9 ответов


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


использовать 404 Если ресурс не существует. Не возвращайся!--1--> С пустым телом.

это сродни undefined vs пустая строка (например,"") в программировании. Хотя они очень похожи, между ними определенно есть разница.

404 означает, что в этом URI ничего не существует (например, неопределенная переменная в программировании). Возвращение 200 С пустым телом означает, что что-то существует и что-то пустые прямо сейчас (как пустая строка в программировании).

404 не означает, что это был"плохой URI". Существуют специальные коды HTTP, предназначенные для ошибок URI (например,414 Request-URI Too Long).


как и в большинстве случаев, "это зависит". Но для меня ваша практика не плоха и не идет против спецификации HTTP per se. Однако давайте проясним некоторые вещи.

во-первых, URI должны быть непрозрачными. Даже если они не непрозрачны для людей, они непрозрачны для машин. Другими словами, разница между http://mywebsite/api/user/13, http://mywebsite/restapi/user/13 это то же самое, что и разница между http://mywebsite/api/user/13 и http://mywebsite/api/user/14 т. е. не то же самое не тот же период. Так что 404 будет полностью подходит для http://mywebsite/api/user/14 (если такой пользователь отсутствует), но не обязательно единственный подходящий ответ.

вы также можете вернуть пустой ответ 200 или более явно ответ 204 (без содержимого). Это передаст клиенту что-то еще. Это будет означать, что ресурс, идентифицированный http://mywebsite/api/user/14 не имеет содержания или по существу ничего. Это означает, что там is такой ресурс. Однако это не обязательно означает, что вы утверждаете, что некоторых пользователей сохранены в хранилище данных с id 14. Это ваша личная забота, а не забота клиента, делающего запрос. Поэтому, если имеет смысл моделировать свои ресурсы таким образом, продолжайте.

есть некоторые последствия для безопасности предоставления вашим клиентам информации, которая облегчила бы им угадать законные URI. Возврат 200 на промахи вместо 404 может дать клиенту подсказку, что по крайней мере http://mywebsite/api/user часть верна. Злоумышленник может просто держать пробуем разные целые числа. Но для меня, злонамеренный клиент сможет угадать http://mywebsite/api/user часть в любом случае. Лучшим средством было бы использовать UUID. то есть http://mywebsite/api/user/3dd5b770-79ea-11e1-b0c4-0800200c9a66 лучше, чем http://mywebsite/api/user/14. Делая это, вы можете использовать свою технику возврата 200 - х годов, не отдавая много.


404 Не Найдена технически означает, что uri в настоящее время карта к ресурсу. В вашем примере я интерпретирую запрос на http://mywebsite/api/user/13 что возвращает 404 подразумевать, что этот url был никогда сопоставлено с ресурсом. Для клиента это должно быть концом разговора.

чтобы решить проблемы с неоднозначностью, вы можете улучшить свой API, предоставив другие коды ответа. Например, предположим, вы хотите разрешить клиентам выпуск GET запрашивает url http://mywebsite/api/user/13, вы хотите сообщить, что клиенты должны использовать канонические url http://mywebsite/restapi/user/13. В этом случае вы можете рассмотреть вопрос о выдаче постоянного перенаправления, вернув 301 Окончательно Перемещено и укажите канонический url в расположение заголовок ответа. Это говорит клиенту, что для будущих запросов следует использовать канонические url.


Это старая, но отличная статья... http://www.infoq.com/articles/webber-rest-workflow говорит об этом...

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


таким образом, по сути, похоже, что ответ может зависеть от того, как формируется запрос.

если запрошенный ресурс является частью URI согласно запросу http://mywebsite/restapi/user/13 и пользователь 13 не существует, тогда 404, вероятно, подходит и интуитивно понятен, потому что URI является представителем несуществующего пользователя / сущности/документа / и т. д. То же самое касается более безопасной техники с использованием GUID http://mywebsite/api/user/3dd5b770-79ea-11e1-b0c4-0800200c9a66 и аргумент api / restapi выше.

однако, если запрашиваемые идентификатор ресурса был включен в заголовок запроса [включите свой собственный пример], или действительно, в URI в качестве параметра, например http://mywebsite/restapi/user/?UID=13 тогда URI все равно будет правильным (потому что концепция пользователя выходит на http://mywebsite/restapi/user/); и поэтому можно ожидать, что ответ будет 200 (с соответствующим подробным сообщением), потому что конкретный пользователь, известный как 13, не существует, но URI существует. Таким образом, мы говорим, что URI хорош, но запрос данных не имеет содержание.

лично 200 все еще не чувствует себя правильно (хотя я ранее утверждал, что это так). Код ответа 200 (без подробного ответа) может привести к тому, что проблема не будет исследована, например, при отправке неправильного идентификатора.

лучшим подходом было бы направить 204 - No Contentответ. Это соответствует описанию w3c *сервер выполнил запрос, но не должен возвращать тело сущности и может захотеть вернуть обновленную метаинформацию.*1 в путаница, на мой взгляд, вызвана записью Википедии с указанием 204-нет содержимого - сервер успешно обработал запрос, но не возвращает какой-либо контент. обычно используется в качестве ответа на успешный запрос удаления. последнее предложение весьма спорно. Рассмотрите ситуацию без этого предложения, и решение легко - просто отправьте 204, если сущность не существует. Существует даже аргумент для возврата 204 вместо 404, запрос имеет был обработан и содержание не было возвращено! Пожалуйста, имейте в виду, что 204 не позволяют содержание в теле ответа

источник

http://en.wikipedia.org/wiki/List_of_HTTP_status_codes 1. http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html


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

Я строю архитектуру микрослужб с API-интерфейсов REST. У меня есть некоторые службы REST GET, они собирают данные из серверной системы на основе параметров запроса.

Я следил за проектными документами REST API, и я отправил обратно HTTP 404 с идеальным сообщением об ошибке JSON клиенту, когда не было данных, которые соответствуют условиям запроса (например выбрана нулевая запись).

когда не было данных для отправки обратно клиенту, я подготовил идеальное сообщение JSON с внутренним кодом ошибки и т. д. сообщить клиенту о причине "не найден" и он был отправлен обратно клиенту с HTTP 404. Это прекрасно работает.

позже я создал клиентский класс REST API, который является простым помощником для скрытия кода, связанного с HTTP-связью, и я использовал этот помощник все время, когда я вызывал свои API rest из моего код.

но мне нужно было написать запутанный дополнительный код только потому, что HTTP 404 имел две разные функции:

  • реальный HTTP 404 когда REST API недоступен в данном url-адресе, он выбрасывается сервером приложений или веб-сервером, где работает приложение REST API
  • клиент получает назад HTTP 404 также, когда нет данных в базе данных на основе условия where запроса.

важно: мой обработчик ошибок REST API ловит все исключения появляется в фоновой службе, что означает, что в случае любой ошибки мой REST API всегда возвращается с идеальным сообщением JSON с деталями сообщения.

это 1-я версия моего клиентского вспомогательного метода, который обрабатывает два разных ответа HTTP 404:

public static String getSomething(final String uuid) {
    String serviceUrl = getServiceUrl();
    String path = "user/" + , uuid);
    String requestUrl = serviceUrl + path;
    String httpMethod = "GET";

    Response response = client
            .target(serviceUrl)
            .path(path)
            .request(ExtendedMediaType.APPLICATION_UTF8)
            .get();

    if (response.getStatus() == Response.Status.OK.getStatusCode()) {
        // HTTP 200
        return response.readEntity(String.class);
    } else {
        // confusing code comes here just because
        // I need to decide the type of HTTP 404...

        // trying to parse response body
        try {
            String responseBody = response.readEntity(String.class);
            ObjectMapper mapper = new ObjectMapper();
            ErrorInfo errorInfo = mapper.readValue(responseBody, ErrorInfo.class);

            // re-throw the original exception
            throw new MyException(errorInfo);

        } catch (IOException e) {
            // this is a real HTTP 404
            throw new ServiceUnavailableError(response, requestUrl, httpMethod);
        }

    // this exception will never be thrown
    throw new Exception("UNEXPECTED ERRORS, BETTER IF YOU DO NOT SEE IT IN THE LOG");
}

но, потому что мой клиент Java или JavaScript может получить два вида HTTP 404, мне нужно проверить тело ответа в случае HTTP 404. Если я могу разобрать затем я уверен, что получил ответ, в котором не было данных для отправки клиенту.

Если я не могу проанализировать ответ, это означает, что я получил настоящий HTTP 404 с веб-сервера (не из приложения REST API).

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

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

поэтому вместо использования HTTP 404 в этих двух разных сценариях я решил, что сделаю следующее:

  • Я больше не использую HTTP 404 в качестве кода HTTP ответа в моем приложении rest.
  • Я собираюсь использовать HTTP 204 (без контента) вместо HTTP 404.

в этом случае код может быть более элегантным:

public static String getString(final String processId, final String key) {
    String serviceUrl = getServiceUrl();
    String path = String.format("key/%s", key);
    String requestUrl = serviceUrl + path;
    String httpMethod = "GET";

    log(requestUrl);

    Response response = client
            .target(serviceUrl)
            .path(path)
            .request(ExtendedMediaType.APPLICATION_JSON_UTF8)
            .header(CustomHttpHeader.PROCESS_ID, processId)
            .get();

    if (response.getStatus() == Response.Status.OK.getStatusCode()) {
        return response.readEntity(String.class);
    } else {
        String body = response.readEntity(String.class);
        ObjectMapper mapper = new ObjectMapper();
        ErrorInfo errorInfo = mapper.readValue(body, ErrorInfo.class);
        throw new MyException(errorInfo);
    }

    throw new AnyServerError(response, requestUrl, httpMethod);
}

Я думаю, что это решает эту проблему лучше.

Если у вас есть любое лучшее решение, Пожалуйста, поделитесь им с нами.


единый идентификатор ресурса является уникальным указателем на ресурс. Плохой URI формы не указывает на ресурс, и поэтому выполнение GET на нем не вернет ресурс. 404 означает, что сервер не нашел ничего, соответствующего запросу-URI. Если вы ввели неправильный URI или плохой URI, это ваша проблема и причина, по которой вы не попали на ресурс, будь то HTML-страница или IMG.


для этого сценария HTTP 404 - это код ответа для ответа от REST API Как 400, 401, 404 , 422 unprocessable лица

используйте обработку исключений, чтобы проверить полное сообщение об исключении.

try{
  // call the rest api
} catch(RestClientException e) {
     //process exception
     if(e instanceof HttpStatusCodeException){
        String responseText=((HttpStatusCodeException)e).getResponseBodyAsString();
         //now you have the response, construct json from it, and extract the errors
         System.out.println("Exception :" +responseText);
     }

}

этот блок исключений дает вам правильное сообщение, брошенное REST API