"정지 처리"에 대한 HTTP 상태 코드


47

최종 처리를 위해 장기 실행 작업 큐를 지원하는 RESTful API를 작성 중입니다.

이 API의 일반적인 워크 플로우는 다음과 같습니다.

  1. 사용자가 양식을 채 웁니다
  2. 고객이 데이터를 API에 게시
  3. API가 202를 반환 함
  4. 고객이 해당 요청에 대한 고유 URL로 사용자를 리디렉션합니다 ( /results/{request_id})
  5. ~ 결국 ~
  6. 클라이언트는 URL을 다시 방문하여 해당 페이지의 결과를 봅니다.

문제는 6 단계에 있습니다. 사용자가 페이지를 방문 할 때마다 API ( GET /api/results/{request_id})에 요청을 제출합니다 . 이상적으로는 지금까지 작업이 완료되었으며 작업 결과와 함께 200 OK를 반환합니다.

그러나 사용자는 빠르며 결과 처리가 아직 완료되지 않은 경우 많은 과장된 새로 고침을 기대합니다.

상태 코드가 다음을 나타내는 최선의 옵션은 무엇입니까?

  • 이 요청이 존재합니다
  • 아직 끝나지 않았습니다.
  • 그러나 그것은 또한 실패하지 않았습니다.

단일 코드가 그 모든 것을 전달할 것으로 기대하지는 않지만 클라이언트가 콘텐츠를 기대하게하는 대신 메타 데이터를 전달할 수있는 무언가를 원합니다.

202를 반환하는 것이 합리적 일 수 있습니다. 왜냐하면 여기에는 다른 의미가 없기 때문입니다. GET요청이므로 "허용되는 것"은 없습니다. 이것이 합리적인 선택일까요?

이 모든 기능에 대한 확실한 대안은 작동하지만 상태 코드의 한 가지 목적을 상실하는 경우 항상 메타 데이터를 포함하는 것입니다.

200 OK

{
    status: "complete",
    data: {
        foo: "123"
    }
}

...또는...

200 OK

{
    status: "pending"
}

그런 다음 클라이언트 측, 나는 (한숨) 것 switchresponse.data.status요청이 완료되었는지 여부를 결정합니다.

이것이 내가해야 할 일입니까? 아니면 더 나은 대안이 있습니까? 이것은 나에게 웹 1.0을 느낀다.


1
그 목적을 위해 1xx 코드가 정확하게 만들어지지 않았습니까?
Andy

@Andy 나는 102를보고 있었지만 WebDAV에 관한 것입니다. 그 외에도, 아닙니다. 그들은 주로 전송 중 통신을위한 것입니다. 웹 소켓 등으로 전환하는 데 유용합니다.
Matthew Haugen

어떤 종류의 지연을 말하고 있습니까? 10 초? 아니면 6 시간? 지연 시간이 짧고 일반적으로 동일한 브라우저 방문 내에서주기적인 폴링이 아닌 긴 폴링 또는 웹 소켓을 수행 할 수 있습니다.
GrandmasterB

@GrandmasterB 잠재적 인 시간입니다. 나는 작업 처리 자체에 대해 책임을지지 않으므로 실제로 좋은 평가는 없지만 시간이 걸릴 것입니다. 그렇지 않으면 첫 번째 POST요청을 열어 둡니다 . 긴 폴링 또는 웹 소켓의 주요 문제는 사용자가 브라우저를 닫고 다시 올 수 있다는 것입니다. 그 당시에 다시 열 수 있었지만 (그것이 내가하는 일입니다.)하지만 소켓을 열기 전에 호출 할 단일 API를 갖는 것이 더 깨끗한 것 같습니다.
Matthew Haugen

답변:


48

HTTP 202 허용 (HTTP / 1.1)

당신은 HTTP 202 Accepted상태를 찾고 있습니다. RFC 2616 참조 :

처리 요청이 승인되었지만 처리가 완료되지 않았습니다.

HTTP 102 처리 (WebDAV)

RFC 2518 은 다음을 사용하도록 제안합니다 HTTP 102 Processing.

102 (처리 중) 상태 코드는 서버가 완료 요청을 수락했지만 아직 완료하지 않았 음을 클라이언트에 알리는 데 사용되는 임시 응답입니다.

그러나주의 사항이 있습니다.

요청이 완료된 후 서버는 반드시 최종 응답을 보내야합니다.

마지막 문장을 해석하는 방법을 잘 모르겠습니다. 서버가 처리하는 동안 아무것도 보내지 않아야 하고 완료 후에 만 응답해야 합니까? 아니면 처리 가 끝날 때만 응답을 강제 종료합니까? 진행 상황을보고하려는 경우 유용 할 수 있습니다. HTTP 102를 보내고 바이트 단위로 (또는 라인 단위로) 응답을 플러시합니다.

예를 들어 길지만 선형적인 프로세스의 경우 각 문자 다음에 플러시하여 100 개의 점을 보낼 수 있습니다. 클라이언트 측 (예 : JavaScript 응용 프로그램)이 정확히 100자를 예상해야한다는 것을 알고 있으면 진행률 표시 줄과 일치시켜 사용자에게 표시 할 수 있습니다.

다른 예는 여러 비선형 단계로 구성된 프로세스와 관련이 있습니다. 각 단계 후에 최종 사용자가 프로세스 진행 상황을 알 수 있도록 사용자에게 표시되는 로그 메시지를 플러시 할 수 있습니다.

점진적 플러싱 문제

이 기술에는 장점 이 있지만 권장하지는 않습니다 . 그 이유 중 하나는 연결을 강제로 열어 두어야하기 때문에 서비스 가용성 측면에서 문제가 생길 수 있으며 확장이 잘되지 않기 때문입니다.

더 나은 접근 방식은 응답을 처리 HTTP 202 Accepted하고 나중에 사용자에게 다시 돌아와서 처리가 종료되었는지 여부를 결정하도록 /process/result하는 것입니다 ( 예 : 프로세스까지 HTTP 404 Not Found 또는 HTTP 409 충돌로 응답 하는 지정된 URI를 반복해서 호출하여) 메시지 큐 서비스 ( :) 또는 WebSocket을 통해 클라이언트를 다시 호출 할 수있는 경우 처리가 완료되면 사용자에게 알리거나 처리가 완료된 경우 사용자에게 알립니다 .

실제 예

비디오를 변환하는 웹 서비스를 상상해보십시오. 진입 점은 다음과 같습니다.

POST /video/convert

HTTP 요청에서 비디오 파일을 가져 와서 마술을합니다. 마술은 CPU를 많이 사용하므로 요청을 전송하는 동안 실시간으로 수행 할 수 없다고 가정 해 봅시다. 즉, 파일이 전송되면 서버는 HTTP 202 AcceptedJSON 콘텐츠로 응답 합니다. "예, 비디오를 받았으며 작업 중입니다. 향후 어딘가에 준비 될 것이며 ID 123을 통해 이용 가능할 것입니다.”

클라이언트는 처리가 완료되면 알림을 받기 위해 메시지 큐를 구독 할 수 있습니다. 완료되면 클라이언트는 다음으로 이동하여 처리 된 비디오를 다운로드 할 수 있습니다.

GET /video/download/123

이는 리드 HTTP 200.

클라이언트가 알림을 받기 전에이 URI를 쿼리하면 어떻게됩니까? HTTP 404실제로 서버는 비디오가 존재하지 않기 때문에 서버가 응답 합니다. 현재 준비 중일 수 있습니다. 요청되지 않았을 수 있습니다. 과거에는 일정 시간이 지난 후 나중에 제거 될 수 있습니다. 중요한 것은 결과 비디오를 사용할 수 없다는 것입니다.

이제 클라이언트가 최종 비디오뿐만 아니라 진행 상황 (메시지 대기열 서비스 또는 이와 유사한 메커니즘이없는 경우 더 중요)에 관심이 있다면 어떻게해야합니까?

이 경우 다른 엔드 포인트를 사용할 수 있습니다.

GET /video/status/123

다음과 비슷한 응답이 발생합니다.

HTTP 200
{
    "id": 123,
    "status": "queued",
    "priority": 2,
    "progress-percent": 0,
    "submitted-utc-time": "2016-04-19T13:59:22"
}

계속해서 요청하면 다음과 같은 진행 상황이 표시됩니다.

HTTP 200
{
    "id": 123,
    "status": "done",
    "progress-percent": 100,
    "submitted-utc-time": "2016-04-19T13:59:22"
}

이러한 세 가지 유형의 요청간에 차이를 만드는 것이 중요합니다.

  • POST /video/convert작업을 대기열에 넣습니다. 한 번만 호출해야합니다. 다시 호출하면 추가 작업이 대기됩니다.
  • GET /video/download/123작업 결과 와 관련이 있습니다 . 리소스 는 비디오입니다. 요청 이전에 요청과 독립적으로 실제 결과 를 준비 하기 위해 처리 과정에서 발생했던 처리 는 여기와 관련이 없습니다. 한 번 또는 여러 번 호출 할 수 있습니다.
  • GET /video/status/123처리 자체에 관한 것이다 . 아무것도 큐에 넣지 않습니다. 결과 비디오에 대해서는 신경 쓰지 않습니다. 리소스 처리 자체이다. 한 번 또는 여러 번 호출 할 수 있습니다.

1
202에 대한 응답으로 의미가 GET있습니까? 그것이 initial을위한 올바른 선택 POST이므로 확실히 그것을 사용하고 있습니다. 그러나 GET특정 요청에서 아무것도 받아들이지 않을 때 "수락되었다"는 말 은 의미 상 의심스러워 보입니다 .
Matthew Haugen

2
@MainMa 내가 말했듯이, POST대기 할 작업을 시작한 다음 GET클라이언트가 세션을 닫은 후에 결과를 얻을 수 있습니다. 404도 내가 고려한 것이지만 요청 발견되어 완료되지 않은 것은 잘못된 것 같습니다 . 대기중인 작업을 찾을 수 없다는 것을 나에게 알릴 것입니다. 매우 다른 상황입니다.
Matthew Haugen

1
@ MatthewHaugen : 당신이 GET부분 을 할 때 , 불완전한 요청 으로 생각하지 말고 작업 결과를 얻는 요청 으로 생각하십시오 . 예를 들어, 비디오 변환을 요청 했는데 5 분이 걸리면 변환 된 비디오를 2 분 후에 요청 하면 비디오가 아직 없기 때문에 HTTP 404 발생합니다. 반면에 작업 자체의 진행을 요청하면 변환 된 바이트 수, 속도 등을 포함하는 HTTP 200이 생성 될 수 있습니다.
Arseni Mourzenko

5
리소스에 대한 HTTP 상태 코드를 아직 사용할 수없는 경우 리소스가 404 응답이 아닌 경우 409 충돌 응답 ( "현재 리소스 상태와 충돌하여 요청을 완료 할 수 없습니다.")을 반환 할 것을 제안합니다. 생성되는 중이기 때문에 존재하지 않습니다.
Brian

1
@Brian 귀하의 의견은이 질문에 대한 합리적인 답변을 드릴 것입니다. "그의 코드는 사용자가 충돌을 해결하고 요청을 다시 제출할 수있을 것으로 예상되는 상황에서만 허용됩니다." "찾을 수 없음"보다 덜 잘못되었습니다. 내 일부는 Retry-After 헤더가 고정 된 409쪽으로 기울어 져 있습니다. 유일한 문제는 GET에 대해 409를 반환하는 것이 이상하게 보이지만 그 이상과 함께 살 수 있다는 것입니다. 미래에 다른 방식으로 정의되지는 않을 것입니다.
Matthew Haugen

5

이 모든 기능에 대한 확실한 대안은 작동하지만 상태 코드의 한 가지 목적을 상실하는 경우 항상 메타 데이터를 포함하는 것입니다.

이것이 올바른 길입니다. 자원이 도메인 특정 로그 (일명 비즈니스 로직)와 관련이있는 상태는 자원 표현의 컨텐츠 유형에 대한 문제입니다.

실제로 다른 두 가지 차이점 개념이 여기에 있습니다. 하나는 자원의 클라이언트와 서버 사이의 상태 전송 상태이고, 다른 하나는 비즈니스 도메인이 해당 자원의 다른 상태를 이해하는 상황에서 자원 자체의 상태입니다. 후자는 HTTP 상태 코드와 관련이 없습니다.

HTTP 상태 코드는 처리되는 리소스의 클라이언트와 서버 간의 상태 전송에 해당하는 리소스의 세부 정보와 독립적으로 일치합니다. 당신 GET이 자원을 당신의 클라이언트가 현재 상태에있는 자원의 표현을 서버에 요구할 때, 그것은 새의 그림 일 수 있고, Word 문서 일 수도 있고, 현재 외부 온도 일 수도 있습니다. HTTP 프로토콜은 중요하지 않습니다. HTTP 상태 코드는 해당 요청의 결과에 해당합니다. DID의 POST서버가 다음 그것을 클라이언트가 볼 수있는 URL을 준 경우 클라이언트에서 서버로 서버에 리소스를 전송? 예? 그렇다면 그것은 201 Created응답입니다.

자원은 현재 '검토 대상'상태 인 항공사 예약일 수 있습니다. 또는 '승인 됨'상태 인 제품 구매 주문일 수 있습니다. 이러한 상태는 도메인에 따라 다르며 HTTP 프로토콜이 아닙니다. HTTP 프로토콜은 클라이언트와 서버 간의 리소스 전송을 처리합니다.

REST와 HTTP의 요점은 프로토콜이 리소스의 세부 사항과 관련이 없다는 것입니다. 이는 도메인 관련 문제와 관련이 없으므로 도메인 관련 문제에 대해 전혀 몰라도 사용할 수 있습니다. 각기 다른 상황 (항공사 예약 시스템, 상상 처리 시스템, 비디오 보안 시스템 등)에서 HTTP 상태 코드의 의미를 해석하지 않습니다.

도메인 특정 항목은 클라이언트와 서버가 Content Type리소스를 기반으로 자신을 파악하는 것 입니다. HTTP 프로토콜은 이것과 무관합니다.

클라이언트가 요청 리소스가 상태를 변경했음을 확인하는 방법에 대해서는 폴링이 클라이언트에서 제어를 유지하고 끊어지지 않은 연결을 가정하지 않기 때문에 최선의 방법입니다. 특히 상태가 바뀔 때까지 몇 시간이 걸리는 경우. REST로 지옥이라고 말하더라도 연결을 열어두고 몇 시간 동안 열어두고 아무것도 잘못되지 않는다고 가정하는 것은 나쁜 생각입니다. 사용자가 클라이언트를 닫거나 네트워크가 종료되면 어떻게됩니까? 세분성이 시간 인 경우 클라이언트는 요청이 '보류 중'에서 '완료'로 변경 될 때까지 몇 분마다 상태를 요청할 수 있습니다.

일을 명확히하는 데 도움이되는 희망


"클라이언트에서 서버로의 POST가 서버로 리소스를 전송 한 후 서버에서 클라이언트가 볼 수있는 URL을 제공 했습니까? 그렇다면? 201 Created 응답입니다." 202 서버가 즉시 자원을 처리하기 위해 작동 할 수없는 경우 OP에 대한 응답으로 승인 됨도 허용됩니다.
Andy

1
문제는 서버가 즉시 작동한다는 것입니다. URL을 사용하여 즉시 리소스를 만듭니다. 자원 상태가 "Pending"(또는 다른 것)입니다. 비즈니스 도메인 상태입니다. HTTP 프로토콜에 관한 한, 서버는 리소스를 생성하고 클라이언트에게 리소스의 URL을 제공하자마자 작동했습니다. 그 자원을 얻을 수 있습니다. POST 요청 자체는 보류 중이 아닙니다. 이것은 두 개의 다른 개념 영역을 분리하여 유지한다는 의미입니다. 클라이언트가 화재를 보내고 있었지만 POST 요청을 잊어 버린 경우 몇 시간 동안 행동하지 않으면 202가 적용됩니다.
Cormac Mulhall

URL이 존재하는지 아무도 신경 쓰지 않지만 리소스가 여전히 처리 중이기 때문에 리소스가 나타내는 데이터를 가져올 수 없습니다. 비디오를 얻는 데 사용될 때까지 URL을 만들지 않을 수도 있습니다.
Andy

리소스가 생성되었으며 "보류 중"상태입니다. 그것은 그 자체로 관련 데이터입니다. 향후 어느 시점에서 서버는 자원 상태를 "완료"(또는 "실패")로 변경할 수 있지만 이는 "자원 작성"이라는 HTTP 도메인 특정 작업과는 다른 개념입니다. 보류는 "요청"자원이되기에 완벽하게 유효한 상태 일 수 있으며, 클라이언트는 서버가 자원을 작성하도록 요청하여 폴링을 알기 위해 이동하도록 요청하기 때문에 서버가 해당 상태에서 자원을 작성했음을 알고 자합니다. 상태가 변경된 경우
Cormac Mulhall

4

이 블로그의 제안이 합리적이라고 생각했습니다 : REST 및 장기 실행 작업 .

요약:

  1. 서버는 클라이언트가 상태를 확인할 수 있도록 "Location"헤더를 URI로 설정하여 코드 "202 Accepted"를 반환합니다 (예 : "/ queue / 12345").
  2. 처리가 완료 될 때까지 서버는 "200 OK"및 작업 상태를 표시하는 일부 응답 데이터로 상태 조회에 응답합니다.
  3. 처리가 완료된 후 서버는 최종 결과에 대한 URI를 포함하는 "303 See Other"및 "Location"을 사용하여 상태 쿼리에 응답합니다.

2

리소스에 대한 HTTP 상태 코드를 아직 사용할 수없는 경우 리소스가 생성되는 동안 리소스가 존재하지 않는 경우 404 응답이 아닌 409 충돌 응답을 반환하는 것이 좋습니다.

로부터 W3 사양 :

10.4.10 409 충돌

리소스의 현재 상태와 충돌하여 요청을 완료 할 수 없습니다. 이 코드는 사용자가 충돌을 해결하고 요청을 다시 제출할 수있는 상황에서만 허용됩니다. 응답 본문에는 충분한 내용이 포함되어야합니다

사용자가 충돌의 원인을 인식 할 수있는 정보. 이상적으로, 응답 엔티티는 사용자 또는 사용자 에이전트가 문제를 해결하기에 충분한 정보를 포함 할 것이다. 그러나 불가능할 수도 있고 필요하지 않을 수도 있습니다.

PUT 요청에 대한 응답으로 충돌이 발생할 가능성이 높습니다. 예를 들어, 버전 관리를 사용 중이고 PUT중인 엔티티에 이전 (타사) 요청으로 작성된 자원과 충돌하는 자원에 대한 변경 사항이 포함 된 경우 서버는 409 응답을 사용하여 요청을 완료 할 수 없음을 표시 할 수 있습니다 . 이 경우 응답 엔티티는 응답 Content-Type에 의해 정의 된 형식으로 두 버전 간의 차이점 목록을 포함 할 수 있습니다.

409 코드가 "사용자가 충돌을 해결하고 요청을 다시 제출할 수있는 상황에서만 허용되기 때문에"이것은 약간 어색합니다. 응답 본문에 "이 리소스는 현재 생성 중입니다. [TIME]에 시작되었으며 [TIME]에 완료 될 것으로 예상되는 메시지 (일부 API의 나머지 부분과 일치하는 응답 형식으로 표시)를 포함하는 것이 좋습니다. 나중에 다시 시도하십시오. "

리소스를 요청하는 사용자가 해당 리소스의 생성을 시작한 사용자 일 가능성이 높은 경우에만 409 접근 방식을 제안합니다. 리소스 생성과 관련이없는 사용자는 404 오류가 덜 혼란 스러울 수 있습니다.


409가 실제로 무엇을 의미하는지에 대한 스트레치처럼 보입니다.
Andy

@ 앤디 : 사실이지만 다른 대안도 마찬가지입니다. 예를 들어, 202는 실제로 처리 결과를 요청한 요청이 아니라 처리 를 시작한 요청에 대한 응답이되어야한다 . 리소스가 발견되지 않았기 때문에 (아직 존재하지 않았기 때문에) 가장 사양에 맞는 응답은 404입니다. API가 404 응답 내에서 관련 API 데이터를 제공하는 것을 막을 것은 없습니다. 4xx / 5xx 응답은 소비하기가 성가신 경향이 있습니다. 일부 언어는 다른 상태 코드를 제공하기보다는 예외를 발생시킵니다.
Brian

2
아니요, 특히 MainMa의 답변의 마지막 몇 단락입니다. 엔드 포인트를 분리하여 요청 상태를 확인하고 비디오 자체를 가져 오십시오. 상태는 동영상과 동일한 리소스가 아니며 자체적으로 처리 할 수 ​​있어야합니다.
Andy
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.