여러 작업이 다른 상태로 완료되면 반환 할 HTTP 상태 코드는 무엇입니까?


72

사용자가 서버에 하나의 HTTP 요청으로 여러 작업을 수행하도록 요청할 수있는 API를 작성 중입니다. 결과는 조치 당 하나의 항목이있는 JSON 배열로 리턴됩니다.

이러한 각 작업은 서로 독립적으로 실패하거나 성공할 수 있습니다. 예를 들어 첫 번째 작업이 성공하고 두 번째 작업의 입력 형식이 잘못되어 유효성을 검사하지 못할 수 있으며 세 번째 작업으로 인해 예기치 않은 오류가 발생할 수 있습니다.

작업 당 하나의 요청이 있으면 상태 코드 200, 422 및 500을 각각 반환합니다. 그러나 요청이 하나만있을 때 어떤 상태 코드를 반환해야합니까?

일부 옵션 :

  • 항상 200을 반환하고 본문에 더 자세한 정보를 제공하십시오.
  • 요청에 둘 이상의 조치가있는 경우에만 위의 규칙을 따르십시오.
  • 모든 요청이 성공하면 200을 반환하고, 그렇지 않으면 500 (또는 다른 코드)을 반환합니까?
  • 작업 당 하나의 요청 만 사용하고 추가 오버 헤드를 수락하십시오.
  • 완전히 다른 것?

3
귀하의 질문으로 다른 하나에 대해 생각하게되었습니다 : programmers.stackexchange.com/questions/309147/…
AilurusFulgens

7
약간뿐만 아니라 관련 : programmers.stackexchange.com/questions/305250/...은 (HTTP 상태 코드와 애플리케이션 코드 사이의 거리에 대한 허용 대답 참조)

4
이러한 요청을 그룹화하여 얻을 수있는 이점은 무엇입니까? 여러 리소스에 대한 트랜잭션과 같은 비즈니스 논리에 관한 것인가 아니면 성능에 관한 것인가? 또는 다른 것?
Luc Franken

5
좋습니다.이 경우 다른 영역에서 해당 성능을 향상시키는 것이 좋습니다. 비즈니스 계층에 이러한 복잡성을 구현하기 전에 낙관적 UI, 요청 일괄 처리, 캐싱 등을 시도하십시오. 대부분의 시간을 잃는 곳에 대한 명확한 통찰력이 있습니까?
Luc Franken

4
... 사람들이 그 상태를 올바르게 볼 수 있기를 기대하지 마십시오. 대부분의 프로그램은 가장 일반적인 프로그램 만 확인하고 예기치 않은 상태 코드가 표시되면 실패하거나 오작동합니다. (DefCon에서 브라우저가 무시하는 임의의 종료 상태를 전송하여 크롤러로부터 사이트를 보호하고 크롤러가 때때로 오류가 발생하여 웹 사이트의 크롤링을 중지하는 이유를 간단히 표시하여 크롤러로부터 사이트를 보호하는 것에 대한 프레젠테이션이 있음을 기억합니다).
Bakuriu

답변:


21

짧고 직접적인 답변

요청이 작업 목록을 실행하는 것에 대해 말하고 있기 때문에 (작업은 여기서 말하는 리소스입니다), 작업 그룹이 실행으로 이동 한 경우 (즉, 실행 결과에 관계없이) 합리적입니다. 응답 상태는입니다 200 OK. 같은 실패 확인 등의 작업 그룹의 실행을 방지 할 문제가 있다면 그렇지 않으면, 작업 개체 , 또는 필요한 서비스, 예를 들어, 다음 응답 상태가 오류를 의미한다 사용할 수 없습니다. 과거에 작업 실행이 시작될 때 수행 할 작업이 요청 본문에 표시되는 것을 보면 실행 결과가 응답 본문에 나열 될 것으로 기대합니다.


길고 철학적 인 답변

HTTP가 설계된 것과 다른 점 때문에이 딜레마가 발생합니다. 자원을 관리하기 위해 상호 작용하지 않고 오히려 원격 메소드 호출의 수단으로 사용하고 있습니다 (매우 이상하지는 않지만 선입견 없이는 제대로 작동하지 않습니다).

위의 내용을 말하고이 답변을 긴 의견으로 안내 할 용기가 없다면 다음은 자원 관리 접근 방식을 따르는 URI 체계입니다.

  • /tasks
    • GET 페이지 매김 된 모든 작업을 나열합니다.
    • POST 하나의 작업을 추가
  • /tasks/task/[id]
    • GET 단일 작업의 상태 객체로 응답
    • DELETE 작업 취소 / 삭제
  • /tasks/groups
    • GET 페이지 매김 된 모든 작업 그룹을 나열합니다.
    • POST 작업 그룹을 추가합니다
  • /tasks/groups/group/[id]
    • GET 작업 그룹의 상태로 응답
    • DELETE 작업 그룹을 취소 / 삭제

이 구조는 자원에 대해 다루지 않고 자원에 대해 이야기합니다. 리소스로 수행되는 작업은 다른 서비스의 문제입니다.

또 다른 중요한 점은 HTTP 요청 처리기에서 오랫동안 차단하지 않는 것이 좋습니다. UI와 마찬가지로 HTTP 인터페이스는 응답 속도가 빨라야합니다 (이 계층은 IO를 처리하기 때문에).

버튼을 클릭 할 때 리소스를 엄격하게 관리하는 HTTP 인터페이스를 설계하는 것은 UI 스레드에서 작업을 옮기는 것만 큼 어렵습니다. HTTP 서버는 요청 핸들러에서 태스크를 실행하지 않고 다른 서비스와 통신하여 태스크를 실행해야합니다. 이것은 얕은 구현이 아니며 방향의 변화입니다.


이러한 URI 체계가 사용되는 방법에 대한 몇 가지 예

단일 작업 실행 및 진행 상황 추적 :

  • POST /tasks 실행할 작업과 함께
    • GET /tasks/task/[id]completed현재 상태 / 진행률을 표시하면서 응답 객체 가 양수 값을 가질 때까지

단일 작업을 실행하고 완료를 기다리는 중 :

  • POST /tasks 실행할 작업과 함께
    • GET /tasks/task/[id]?awaitCompletion=truecompleted양수 값을 가질 때까지 (시간 종료 가능성이 있으므로 이것이 반복되어야 함)

작업 그룹 실행 및 진행 상황 추적 :

  • POST /tasks/groups 실행할 작업 그룹과 함께
    • GET /tasks/groups/group/[groupId]응답 객체 completed속성에 개별 작업 상태를 표시하는 값이 있을 때까지 (예 : 5 개 중 3 개 작업 완료)

작업 그룹에 대한 실행 요청 및 완료 대기

  • POST /tasks/groups 실행할 작업 그룹과 함께
    • GET /tasks/groups/group/[groupId]?awaitCompletion=true 완료를 나타내는 결과로 응답 할 때까지 (시간 종료 가능성이 있으므로 루프를 반복해야하는 이유)

의미 적으로 의미가있는 것에 대해 이야기하는 것이 이것에 접근하는 올바른 방법이라고 생각합니다. 감사!
Anders

2
이 답변이 아직 없다면 제안하려고했습니다. 는 불가능 하나의 HTTP 요청에서 여러 요청을 할 수 있습니다. 반면에 "다음 작업을 수행하고 결과가 무엇인지 알려주십시오" 라는 단일 HTTP 요청 을 만드는 것이 완벽하게 가능합니다 . 그리고 이것은 여기서 일어나고 있습니다.
Martin Kochanski

나는이 답변이 가장 많은 표를 얻지 못했다는 것을 받아 들일 것입니다. 다른 답변도 훌륭하지만 이것이 HTTP의 의미에 대한 유일한 이유라고 생각합니다.
Anders

87

본인의 투표는 이러한 작업을 별도의 요청으로 나누는 것입니다. 그러나 너무 많은 왕복이 우려되는 경우 HTTP 응답 코드 207-다중 상태를 발견했습니다.

이 링크에서 복사 / 붙여 넣기 :

다중 상태 응답은 다중 상태 코드가 적절한 상황에서 다중 자원에 대한 정보를 전달합니다. 기본 다중 상태 응답 본문은 'multistatus'루트 요소가있는 text / xml 또는 application / xml HTTP 엔티티입니다. 추가 요소에는 메소드 호출 중에 생성 된 200, 300, 400 및 500 시리즈 상태 코드가 포함됩니다. 100 시리즈 상태 코드는 '응답'XML 요소에 기록되어서는 안된다.

'207'이 전체 응답 상태 코드로 사용되지만 수신자는 메소드 실행의 성공 또는 실패에 대한 추가 정보를 얻기 위해 다중 상태 응답 본문의 내용을 참조해야합니다. 응답은 성공, 부분적 성공 및 실패 상황에서도 사용될 수 있습니다.


22
207OP가 원하는 것 같지만 실제로 다중 요청 방식을 사용하는 것은 나쁜 생각이라고 강조하고 싶습니다. 성능이 우려되는 경우 클라우드 스타일의 수평 확장 가능 시스템 (HTTP 기반 시스템이
훌륭함

44
@DavidGrinberg 더 이상 동의하지 않았습니다. 개별 조치가 저렴하면 요청을 처리하는 오버 헤드가 조치 자체보다 훨씬 더 비쌀 수 있습니다. 각 행이 별도의 요청으로 전송되기 때문에 데이터베이스에서 여러 행을 업데이트하는 것이 행당 별도의 트랜잭션을 사용하여 수행되는 시나리오가 발생할 수 있습니다. 이것은 끔찍하게 비효율적 일뿐만 아니라 필요한 경우 여러 행을 원자 적으로 업데이트 할 수 없다는 것을 의미합니다. 수평 스케일링은 중요하지만 효율적인 설계를 대체하지는 않습니다.
kasperd

4
잘 말하고 성능 및 원자 성과 같은 비즈니스 요구의 현실에 무지한 사람들이 수행 한 REST API 구현의 일반적인 문제를 지적했습니다. 예를 들어, OData REST 사양은 한 번의 호출로 여러 작업을위한 배치 형식을 갖습니다. 실제로 필요한 경우가 있습니다.
TomTom

8
@TomTom, OP 원 자성을 원하지 않습니다 . 원자 연산의 상태가 하나뿐이므로 설계하기가 훨씬 쉽습니다. 또한 HTTP 사양은 HTTP / 2 멀티플렉싱을 통해 성능에 대한 일괄 처리 작업을 허용합니다. 당연히 HTTP / 2 지원은 또 다른 문제이지만 사양에서는 허용됩니다.
Paul Draper

2
@David 과거에 일부 HPC 문제를 해결해 본 경험에 따르면 단일 바이트 전송 비용은 천 단위 전송 비용과 거의 동일합니다 (다른 전송 매체는 확실히 다른 오버 헤드를 갖지만 이것보다 낫지는 않습니다). 따라서 성능이 중요하다면 여러 요청을 보내는 데 큰 오버 헤드가없는 방법을 알 수 없습니다. 이제 동일한 연결을 통해 여러 요청을 멀티플렉싱 할 수 있다면이 문제는 사라질 것입니다. 그러나 이해하는 것처럼 HTTP / 2의 옵션 일 뿐이며 지원이 다소 제한적입니다. 아니면 뭔가 빠졌습니까?
Voo

24

다중 상태는 옵션이지만 모든 요청이 성공하면 200 (모두 정상)을 반환하고 그렇지 않으면 오류 (500 또는 207)를 반환합니다.

표준 사례는 일반적으로 200이어야합니다-모든 것이 작동합니다. 그리고 고객은이를 확인하기 만하면됩니다. 오류가 발생한 경우에만 500 (또는 207)을 반환 할 수 있습니다. 적어도 하나의 오류가 발생하면 207이 올바른 선택이라고 생각하지만 전체 패키지를 하나의 트랜잭션으로 볼 경우 500을 보낼 수도 있습니다.-클라이언트는 오류 메시지를 어느 쪽이든 해석하려고합니다.

왜 항상 207을 보내지 않습니까? -표준 케이스는 쉽고 표준이어야합니다. 예외적 인 경우는 예외적 일 수 있습니다. 예외적 인 상황이 정당한 경우, 고객은 응답 기관을 읽고 복잡한 결정을 내려야합니다.


6
동의하지 않습니다. 하위 요청 1과 3이 성공하면 결합 된 자원을 얻게되고 결합 된 응답을 확인해야합니다. 고려해야 할 사례가 하나 더 있습니다. 응답 = 200 또는 하위 응답 1 = 200이면 요청 1이 성공한 것입니다. response = 200 또는 subresponse 2 = 200 인 경우, 서브 응답을 테스트하는 대신 요청 2가 성공합니다.
gnasher729

1
@ gnasher729 그것은 응용 프로그램에 따라 다릅니다. 모든 요청이 성공했을 때 다음 단계로 넘어갈 사용자 중심 동작을 상상해보십시오. -문제가 발생한 경우 (전역 상태 <= 200) 자세한 오류를 표시하고 워크 플로를 변경해야하며 "handleAllOk"함수가 아닌 "handleMixedState"함수에 있으므로 각 하위 요청에 대해 한 번만 확인하면됩니다. .
팔코

그것은 실제로 그것이 무엇을 의미하는지에 달려 있습니다. 예를 들어 거래 전략을 제어하는 ​​엔드 포인트가 있습니다. 한 번의 실행으로 식별자 목록을 "시작"할 수 있습니다. 리턴 200은 조작 (처리)이 성공했지만 모든 것이 성공적으로 시작되지는 않음을 의미합니다. 시작하는 데 몇 초가 걸리므로 즉각적인 결과 (시작될)에서도 btw.를 볼 수 없습니다. 다중 작업 호출의 의미는 시나리오에 따라 다릅니다.
TomTom

서버가 개별 요청을 시도하지 않고 일반적인 오류를 반환 할 수 있도록 일반적인 문제 (예 : 데이터베이스 다운)가 있으면 500을 보낼 것입니다. -사용자에 대해 3 가지 결과가 있으므로 1. 모두 정상, 2. 일반 문제, 아무것도 작동하지 않음, 3. 일부 요청이 실패했습니다. -> 일반적으로 완전히 다른 프로그램 흐름으로 이어집니다.
팔코

1
207 = 각 요청에 대한 개별 상태입니다. 기타 사항 : 반환 된 상태는 각 요청에 적용됩니다. ≥ (500) (200)에 대한 감각, 401, 만든다
gnasher729

13

한 가지 옵션은 항상 상태 코드 200을 반환 한 다음 JSON 문서 본문에서 특정 오류를 반환하는 것입니다. 이것은 정확히 일부 API가 설계된 방식입니다 (항상 상태 코드 200을 반환하고 본문에 오류를 전달합니다). 다양한 접근 방식에 대한 자세한 내용은 http://archive.oreilly.com/pub/post/restful_error_handling.html을 참조하십시오.


2
이 경우, 내가 사용의 생각처럼 200나타 내기 위해 모두가 잘 요청이 수신 및 유효입니다 (즉, 거래의 결과), 그리고 그 요청에 무슨 일이 있었는지에 대한 세부 정보를 제공하기 위해 JSON을 사용합니다.
rickcnagy

4

neilsimp1이 정확하다고 생각하지만, 보낼 수있는 방식으로 전송되는 데이터를 다시 디자인하는 것이 좋습니다. 206 - Accepted 나중에 데이터를 처리 . 콜백이있을 수 있습니다.

단일 요청으로 여러 작업을 보내려고 할 때의 문제는 각 작업마다 자체 "상태"가 있어야한다는 사실입니다.

CSV 가져 오기를 보면 (OP가 무엇인지 실제로 알지 못하지만 간단한 버전입니다). CSV를 게시하고 206을 다시 가져옵니다. 나중에 CSV를 가져올 수 있으며 행당 오류를 표시하는 URL에 대해 GET (200)을 사용하여 가져 오기 상태를 가져올 수 있습니다.

POST /imports/ -> 206
GET  /imports/1 -> 200
GET  /imports/1/errors -> 200 -> Has a list of errors

이 동일한 패턴은 많은 배치 변경에 적용될 수 있습니다

POST /operations/ -> 206
GET  /operations/1 -> 200
GET  /operations/1/errors -> 200 - > Has a list of errors.

POST를 처리하는 코드는 작업 데이터의 형식이 유효한지 확인하면됩니다. 그런 다음 나중에 작업이 실행될 수 있습니다. 예를 들어 지상 근무자에서는 쉽게 확장 할 수 있습니다. 그런 다음 언제든지 원할 때 작업 상태를 확인할 수 있습니다. 폴링 또는 콜백, 스트림 또는 일련의 작업이 완료 될 때 알아야 할 사항을 사용할 수 있습니다.


2

이미 많은 좋은 답변이 있지만 한 가지 측면이 없습니다.

고객이 기대하는 계약은 무엇입니까?

HTTP 리턴 코드는 최소한 성공 / 실패 구별을 나타내므로 "가난한 사람의 예외"의 역할을합니다. 그러면 200은 "계약이 완전히 이행 됨"을 의미하고 4xx 또는 5xx는 이행이 실패했음을 나타냅니다.

순진하게, 나는 당신의 다중 액션 요청의 계약이 "내 모든 작업을 수행"할 것으로 예상하고, 그 중 하나가 실패하면 요청은 (완전히) 성공적이지 못했습니다. 일반적으로 클라이언트는 200을 "모두 괜찮습니다"라고 이해하고 400 및 500 제품군의 코드는 (부분적) 실패의 결과에 대해 생각하게 만듭니다. 따라서 "모든 작업 완료"에 200을 사용하고 부분 실패의 경우 500에 설명 응답을 사용하십시오.

다른 가상 계약은 "모든 작업을 시도"하는 것일 수 있습니다. 그런 다음 조치 중 일부가 실패하면 계약과 완전히 일치합니다. 따라서 개별 작업에 대한 성공 / 실패 정보를 찾을 수있는 결과 문서와 200을 항상 반환합니다.

따라서 따라야 할 계약은 무엇입니까? 둘 다 유효하지만 첫 번째 것 (모든 것이 완료 된 경우에만 200)은 나에게 더 직관적이며 일반적인 소프트웨어 패턴에 더 적합합니다. 그리고 서비스가 모든 작업을 완료 한 대부분의 경우 클라이언트가 해당 사례를 감지하는 것이 간단합니다.

마지막으로 중요한 측면 : 계약 결정을 고객에게 어떻게 전달합니까? 예를 들어 Java에서는 "doAll ()"또는 "tryToDoAll ()"과 같은 메소드 이름을 사용합니다. HTTP에서 클라이언트 개발자가 이름을보고 읽고 이해하기를 바라며 끝점 URL의 이름을 적절하게 지정할 수 있습니다. 가장 놀라운 계약을 선택해야하는 또 하나의 이유.


0

대답:

작업 당 하나의 요청 만 사용하고 추가 오버 헤드를 수락하십시오.

상태 코드는 한 작업의 상태를 설명합니다. 따라서 요청 당 하나의 작업을 수행하는 것이 좋습니다.

여러 개의 독립적 인 작업은 요청-응답 모델 및 상태 코드의 기반이되는 원칙을 위반합니다. 당신은 자연과 싸우고 있습니다.

HTTP / 1.1 및 HTTP / 2는 HTTP 요청의 오버 헤드를 훨씬 낮추었습니다. 독립 요청 일괄 처리가 권장되는 상황은 거의 없습니다.


그것은 말했다

(1) PATCH 요청 ( RFC 5789 )으로 여러 가지 수정을 할 수 있습니다 . 그러나이를 위해서는 변경 사항이 독립적이지 않아야합니다. 그것들은 원자 적으로 (모두 또는 전혀) 적용됩니다.

(2) 다른 사람들은 207 다중 상태 코드를 지적했습니다. 그러나 이것은 HTTP의 확장 인 WebDAV ( RFC 4918 )에 대해서만 정의됩니다 .

207 (Multi-Status) 상태 코드는 여러 개의 독립적 인 작업에 대한 상태를 제공합니다 (자세한 내용은 섹션 13 참조).

...

다중 상태 응답은 다중 상태 코드가 적절한 상황에서 다중 자원에 대한 정보를 전달합니다. 'multistatus'루트 [XML] 요소에는 개별 자원에 대한 정보가있는 순서대로 0 개 이상의 '응답'요소가 있습니다.

207 WebDAV XML 응답은 WebDAV가 아닌 API의 오리만큼 이상합니다. 이러지 마


1
당신은 본질적으로 @Anders에 XY 문제 가 있다고 주장하고 있습니다 . 당신이 옳을 수도 있지만, 불행히도, 이것은 실제로 그가 요청한 질문 (다중 액션 요청에 어떤 상태 코드를 사용할지)에 대답하지 않았다는 것을 의미합니다.
Azuaron

2
@Azuaron, 어린이를 때리는 데 가장 적합한 벨트 종류는 무엇입니까? "N / A"가 적절한 대답이라고 생각합니다. 또한 Andres는 아이디어 목록에 여러 요청을 포함 시켰습니다. 나는 전적으로 그 옵션을지지했다.
Paul Draper

나는 그가 그것을 나열하는 것을 어떻게 든 놓쳤다. 그럴 때는 바보 같은 질문이라고 주장합니다, 재판장 님!
Azuaron

1
@ Azuaron 나는 이것이 올바른 대답이라고 절대적으로 생각합니다. 내가 잘못하고 있다면 누군가가 그렇게 말하기를 원하고 절벽에서 가장 잘 운전하는 방법에 대한 지시를하지 마십시오.
Anders

1
Content-Type 헤더가 올바르게 설정되어 있고 클라이언트가 요청한 내용 (Accept header)과 일치하는 한 207 응답에서 JSON을 보내는 것을 금지하는 것은 없습니다.
고인돌

0

한 번의 요청으로 여러 작업을 수행해야하는 경우 백엔드의 트랜잭션에서 모든 작업을 래핑하지 않는 이유는 무엇입니까? 그런 식으로 그들은 모두 성공하거나 모두 실패합니다.

API를 사용하는 클라이언트로서 API 호출에서 완전한 성공 또는 실패를 처리 할 수 ​​있습니다. 가능한 결과 상태를 모두 처리해야하기 때문에 부분적인 성공은 다루기가 어렵습니다.


2
요청이 원자 적이어야한다고 가정하면이 질문을 게시하지 않았을 것입니다.
Andy

@Andy 아마도, 그러나 당신은 그가 그러한 디자인의 모든 의미를 고려했다고 생각할 수 없습니다.
Dean

요청은 원 자성이 아니어야합니다. 예를 들어 # 2가 실패하더라도 # 1의 변경 사항은 계속 유지됩니다. 따라서 하나의 트랜잭션으로 모든 것을 감싸는 것은 옵션이 아닙니다.
Anders
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.