[web-services] REST API 404 : 잘못된 URI입니까, 아니면 리소스가 없습니까?

REST API를 작성 중이지만 문제가 발생했습니다.

REST API를 설계 할 때 허용되는 관행은 요청 된 자원이 존재하지 않으면 404가 리턴되는 것입니다.

그러나 나에게 이것은 불필요한 모호성을 추가합니다. HTTP 404는 전통적으로 잘못된 URI와 관련이 있습니다. 그래서 사실상 우리가 말하고있는 “어느 쪽이든 당신은 바로 이곳에 도착하지만, 특정 기록이 존재하지 않는, 또는 그러한 위치가 Internets에 없다! 정말 아니에요 확인하는 일 …”

다음 URI를 고려하십시오.

http://mywebsite/api/user/13

404를 다시 받으면 사용자 13이 존재하지 않기 때문입니까? 또는 내 URL 은 다음과 같아야합니다 .

http://mywebsite/restapi/user/13

과거 HTTP 200 OK에는 레코드가 존재하지 않으면 응답 코드 와 함께 NULL 결과를 반환했습니다 . 반드시 받아 들여지는 것은 아니지만 간단하고 제 의견으로는 매우 깨끗합니다. 그러나 이것을하는 더 좋은 방법이 있습니까?



답변

404는 HTTP 응답 코드입니다. 또한 개발자에게 표시 될보다 의미있는 오류 메시지가있는 응답 본문 및 / 또는 기타 헤더를 ​​제공 할 수 있습니다.


답변

404자원이없는 경우 사용하십시오 . 200빈 몸으로 돌아 오지 마십시오 .

이것은 프로그래밍에서 undefined빈 문자열 (예 :)과 유사합니다 "". 매우 유사하지만 분명히 차이가 있습니다.

404는 프로그래밍에 정의되지 않은 변수와 같이 해당 URI에 아무것도 존재하지 않음을 의미합니다. 200빈 본문 으로 돌아온다 는 것은 무언가가 존재하고 무언가가 지금 비어 있음을 의미합니다 (프로그래밍의 빈 문자열과 같이).

404“잘못된 URI”라는 의미는 아닙니다. URI 오류를위한 특수한 HTTP 코드가 있습니다 (예 🙂 414 Request-URI Too Long.


답변

대부분의 경우와 마찬가지로 “의존합니다”. 그러나 나에게 당신의 연습은 나쁘지 않으며 HTTP 사양 자체 에 위배되지 않습니다 . 그러나 몇 가지 사항을 정리하겠습니다.

먼저 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 (No Content) 응답을 반환 할 수도 있습니다. 이것은 클라이언트에게 다른 것을 전달할 것입니다. 이는 식별 된 자원 http://mywebsite/api/user/14이 내용이 없거나 본질적으로 아무것도 아니라는 것을 의미합니다 . 그것은 거기 있음을 의미 하는가 이다 이러한 자원. 그러나 반드시 ID 14의 데이터 저장소에 일부 사용자가 있다고 주장하는 것은 아닙니다. 이는 고객이 요청하는 것이 아니라 개인적인 문제입니다. 리소스를 모델링하는 것이 합리적이라면 계속 진행하십시오.

고객에게 합법적 인 URI를 쉽게 추측 할 수 있도록 정보를 제공하는 데 약간의 보안 관련 사항이 있습니다. 404 대신 미스에 200을 반환하면 클라이언트가 적어도 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가 현재 리소스에 매핑 되지 않았 음을 의미 합니다. 귀하의 예에서 404http://mywebsite/api/user/13반환 하는 요청을 해석 하여이 URL이 리소스에 매핑 되지 않았 음 을 나타냅니다. 클라이언트에게는 이것이 대화의 끝이어야합니다.

모호한 문제를 해결하기 위해 다른 응답 코드를 제공하여 API를 향상시킬 수 있습니다. 예를 들어, 클라이언트가 url을 GET 요청을 발행하도록 허용 http://mywebsite/api/user/13하고 클라이언트가 표준 url을 사용해야한다는 통신을 원한다고 가정하십시오 http://mywebsite/restapi/user/13. 이 경우 영구적으로 301 Moved Permanently 를 반환하여 영구 경로 재 지정을 고려 하고 응답 의 Location 헤더에 정식 URL을 제공 할 수 있습니다. 이것은 클라이언트에게 향후 요청에 대해 표준 URL을 사용해야한다고 알려줍니다.


답변

본질적으로 응답은 요청이 어떻게 형성되는지에 달려 있다고 들립니다.

요청 된 자원이 요청에 따라 URI의 일부를 형성 http://mywebsite/restapi/user/13하고 사용자 (13)가 존재하지 않는 경우, URI는 존재하지 않는 사용자 / 엔티티 / 문서 / 등을 나타 내기 때문에 404가 적절하고 직관적 일 수있다. GUID http://mywebsite/api/user/3dd5b770-79ea-11e1-b0c4-0800200c9a66와 위의 api / restapi 인수를 사용하는보다 안전한 기술도 마찬가지입니다 .

그러나 요청 된 리소스 ID가 요청 헤더 (자신의 예제 포함)에 포함되거나 실제로 URI에 매개 변수 http://mywebsite/restapi/user/?UID=13로 포함 된 경우 URI는 여전히 정확합니다 (USER의 개념이에서 종료되기 때문에 http://mywebsite/restapi/user/). 따라서 13으로 알려진 특정 사용자는 존재하지 않지만 URI는 존재하기 때문에 응답은 200 (적절한 자세한 메시지 포함) 일 것으로 예상 될 수 있습니다. 이런 식으로 URI는 양호하지만 데이터 요청에는 내용이 없습니다.

개인적으로 200은 여전히 ​​옳지 않다고 생각합니다 (이전에 주장 했음에도 불구하고). 200 응답 코드 (자세한 응답 없음)는 예를 들어 잘못된 ID가 전송 될 때 문제를 조사하지 못하게 할 수 있습니다.

더 좋은 방법은 204 - No Content응답 을 보내는 것 입니다. 이 서버는 요청을 이행했지만 entity-body를 반환 할 필요가 없으며 업데이트 된 메타 정보를 반환 할 수 있습니다 * W3C의 설명을 준수합니다. * 1 혼동, 내 의견이 진술 위키 백과 항목에 의해 발생에 204 없음 콘텐츠 -서버가 요청을 성공적으로 처리했지만 내용을 반환하지 않습니다. 일반적으로 성공적인 삭제 요청에 대한 응답으로 사용됩니다 .마지막 문장은 논쟁의 여지가 있습니다. 해당 문장이없는 상황을 고려하면 해결 방법이 쉽습니다. 엔티티가 존재하지 않으면 204 만 보내십시오. 404 대신 204를 반환한다는 주장조차 있습니다. 요청이 처리되었으며 내용이 반환되지 않았습니다! 204는 응답 본문의 내용을 허용하지 않습니다.

출처

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


답변

그것은 매우 오래된 게시물이지만 비슷한 문제에 직면하여 내 경험을 여러분과 공유하고 싶습니다.

나머지 API를 사용하여 마이크로 서비스 아키텍처를 구축 중입니다. 나머지 GET 서비스가 있으며 요청 매개 변수를 기반으로 백엔드 시스템에서 데이터를 수집합니다.

나머지 API 디자인 문서를 따르고 쿼리 조건에 맞는 데이터가 없을 때 완벽한 JSON 오류 메시지와 함께 HTTP 404를 클라이언트에 다시 보냈습니다 (예 : 0 레코드 선택).

클라이언트로 전송할 데이터가 없을 때 내부 오류 코드 등을 포함한 완벽한 JSON 메시지를 준비하여 “Not Found”의 이유를 클라이언트에게 알리고 HTTP 404를 사용하여 클라이언트로 다시 보냈습니다. 잘 작동합니다.

나중에 HTTP 통신 관련 코드를 숨기는 쉬운 도우미 인 나머지 API 클라이언트 클래스를 만들었으며 코드에서 나머지 API를 호출 할 때이 도우미를 항상 사용했습니다.

그러나 HTTP 404에는 두 가지 기능이 있기 때문에 혼란스러운 추가 코드를 작성해야했습니다.

  • 제공된 URL에서 나머지 API를 사용할 수없는 경우 실제 HTTP 404는 나머지 API 응용 프로그램이 실행되는 응용 프로그램 서버 또는 웹 서버에서 발생합니다.
  • 클라이언트는 쿼리의 위치 조건에 따라 데이터베이스에 데이터가없는 경우에도 HTTP 404를 가져옵니다.

중요 : 내 나머지 API 오류 처리기는 백엔드 서비스에 나타나는 모든 예외를 포착합니다. 즉, 오류가 발생하면 나머지 API는 항상 메시지 세부 정보가 포함 된 완벽한 JSON 메시지로 반환됩니다.

이것은 두 가지 다른 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의 경우 응답 본문을 확인해야합니다. 응답 본문을 구문 분석 할 수 있으면 응답이있는 곳에서 응답을 얻었습니다. 클라이언트에게 다시 보낼 데이터가 없습니다.

응답을 파싱 할 수 없다면 웹 서버 (나머지 API 응용 프로그램이 아닌)에서 실제 HTTP 404를 다시 가져 왔습니다.

너무 혼란스럽고 클라이언트 응용 프로그램은 항상 HTTP 404의 실제 이유를 확인하기 위해 추가 구문 분석을 수행해야합니다.

솔직히 나는이 솔루션을 좋아하지 않습니다. 혼란스럽고 항상 고객에게 여분의 헛소리 코드를 추가해야합니다.

따라서이 두 가지 시나리오에서 HTTP 404를 사용하는 대신 다음을 수행하기로 결정했습니다.

  • 더 이상 나머지 응용 프로그램에서 HTTP 404를 응답 HTTP 코드로 사용하지 않습니다.
  • HTTP 404 대신 HTTP 204 (No Content)를 사용하려고합니다.

이 경우 클라이언트 코드가 더 우아해질 수 있습니다.

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);
}

이것이 문제를 더 잘 처리한다고 생각합니다.

더 나은 솔루션이 있으면 공유하십시오.


답변

이 오래되었지만 훌륭한 기사 … http://www.infoq.com/articles/webber-rest-workflow 는 이것에 대해 말합니다 …

404 찾을 수 없음-서비스가 너무 게 으르거나 안전하여 요청이 실패한 이유를 알 수 있지만 이유가 무엇이든 처리해야합니다.