엔티티 본문이 HTTP DELETE 요청에 허용됩니까?


717

HTTP DELETE 요청을 발행 할 때 요청 URI는 삭제할 자원을 완전히 식별해야합니다. 그러나 요청의 엔터티 본문의 일부로 추가 메타 데이터를 추가 할 수 있습니까?


4
ASP.NET에서 WebApi 2 FromBody 매개 변수는 HttpDelete 엔드 포인트에 대해 무시됩니다.
Jenny O'Reilly

2
비슷한 문제가 있지만 사례가 다릅니다. 백 개의 객체를 삭제하려고 할 때 일괄 삭제 요청을 발행하려고합니다. 확실히 HTTP 2.0 이전의 네트워크에서 성능이 크게 향상되었습니다.
Singagirl

1
HTTP / 2가 변경 되었습니까?
Jyotman Singh

답변:


570

사양 은 명시 적으로 금지하거나 권장하지 않으므로 허용된다고 말하는 경향이 있습니다.

Microsoft는 동일한 방식으로 (청중의 불평 소리를들을 수 있음) MSDN 문서 에서 AELE.NET Data Services FrameworkDELETE 방법에 대해 설명합니다 .

삭제 요청에 엔티티 본문이 포함 된 경우 본문은 무시됩니다. [...]

또한 요청과 관련하여 RFC2616 (HTTP 1.1)의 내용은 다음과 같습니다.

  • 엔티티 본체 때만 존재 메시지 본문은 본 인 (7.2)
  • 메시지 본문 의 존재는 Content-Length또는 Transfer-Encoding헤더를 포함함으로써 알린다 (4.3 절)
  • 메시지 본문이 요청 방법의 지정은 송신을 허용하지 않을 경우 포함되지 않아야 엔티티 본체 (섹션 4.3)
  • 엔티티 바디가 명시 적으로 금지되어 TRACE 만, 다른 모든 요청의 유형 (제 9, 특히 9.8)를 제한없는되는 요청

응답을 위해 다음과 같이 정의되었습니다.

  • 되든지 관계없이 메시지 본문을 포함하는 두 요청 방법에 의존 하고 응답 상태 (4.3 절)
  • 메시지 본문을 명시 적으로 (특히 제 9, 9.4) HEAD 요청에 대한 응답으로 금지
  • 메시지 본문을 명시 1XX (정보) (204) (내용이없는)에서 금지하고 (304) (개질되지 않음) 응답 (섹션 4.3)되고
  • 길이가 0 일 수 있지만 다른 모든 응답에는 메시지 본문이 포함됩니다 (4.3 절).

7
@Jason 확실히. 사용자 지정 헤더를 사용하여 추가 데이터를 전달할 수도 있지만 요청 본문을 사용하지 않는 이유는 무엇입니까?
Tomalak

86
스펙이 DELETE 요청에 메시지 본문이있는 것을 금지하지는 않지만 4.3 절에서는 DELETE 엔티티 본문에 대한 "정의 된 의미"가 없으므로 서버가 본문을 무시해야한다고 표시하는 것 같습니다 . 요청에 대한 메시지 본문. 요청 방법에 엔티티 본문에 대해 정의 된 의미가 포함되어 있지 않으면 요청을 처리 할 때 메시지 본문을 무시해야합니다 . "
shelley

72
많은 고객이 본문과 함께 DELETE를 보낼 수도 없습니다. 이것은 안드로이드에서 나를 태워 버렸습니다.
Karmic Coder

1
@ KarmicCoder : 좋은 지적입니다. 자세한 정보 : 안드로이드 HTTP DELETE 요청을 보내기 .
MS Dousti

2
HTTP 스펙과 혼합 된 구현에 대한 많은 토론. 고객은 사양을 해석하는 방식으로 구현하고 사양의 의미와 혼동하지 마십시오. 사실은 스펙이 이것을 모호하게 만듭니다. 엔티티-바디에 대한 정의 된 의미가 없기 때문에 무시되어야한다는 의미에 대한 해석에 동의하지 않습니다. 나는 사람들이 존재하는 고객 특정 해석 (Jersey, Android 테스트 클라이언트 등)에서 거꾸로 노력하고 있으며 사양에 충실하려고 시도하기보다는 해석을 정당화하려고 노력한다고 생각합니다. 인간은 오류가 있습니다.
Gibron

169

HTTP 1.1 스펙 ( RFC 7231 )에 대한 최신 업데이트 는 DELETE 요청에서 엔티티 본문을 명시 적으로 허용합니다.

DELETE 요청 메시지 내의 페이로드에는 정의 된 의미가 없습니다. DELETE 요청에서 페이로드 본문을 전송하면 일부 기존 구현에서 요청을 거부 할 수 있습니다.


3
승인되지 않은 최신 사양의 사양은이 요구 사항을 제거합니다. 승인 된 최신 버전은 여전히 ​​위에서 인용 한 RFC2616입니다.
BishopZ

4
어떤 버전? 버전 20은 여전히 ​​위에서 링크 한 버전 19와 동일한 문구를 갖습니다. "DELETE 요청의 본문에는 정의 된 의미가 없습니다. DELETE 요청에서 본문을 전송하면 일부 기존 구현으로 인해 요청이 거부 될 수 있습니다."

11
버전 26에서는 신체를 허용 할 수 있다고 제안합니다. A payload within a DELETE request message has no defined semantics; sending a payload body on a DELETE request might cause some existing implementations to reject the request.따라서 이전 버전과의 호환성 경고가 제공되므로 다음 표준에서 다음과 같이 말할 것입니다. 'yep! DELETE몸을 가질 수 있습니다`.
Pure.Krome

4
RFC 7231 섹션 4.3.5 는 버전 26의 언어를로 마무리합니다 A payload within a DELETE request message has no defined semantics. 그래서 몸이 허용됩니다.
mndrix

6
본문은 허용되지만 요청과 관련이 없어야합니다. 그것을 사용하는 데 아무런 의미가 없습니다.
Evert


50

삭제 요청에서 본문을 사용하는 한 가지 이유는 낙관적 동시성 제어입니다.

레코드 버전 1을 읽습니다.

GET /some-resource/1
200 OK { id:1, status:"unimportant", version:1 }

동료가 레코드 버전 1을 읽습니다.

GET /some-resource/1
200 OK { id:1, status:"unimportant", version:1 }

동료가 레코드를 변경하고 데이터베이스를 업데이트하여 버전을 2로 업데이트합니다.

PUT /some-resource/1 { id:1, status:"important", version:1 }
200 OK { id:1, status:"important", version:2 }

레코드를 삭제하려고합니다.

DELETE /some-resource/1 { id:1, version:1 }
409 Conflict

낙관적 잠금 예외가 발생합니다. 레코드를 다시 읽고 중요한지 확인하고 삭제하지 마십시오.

이를 사용하는 또 다른 이유는 한 번에 여러 레코드를 삭제하는 것입니다 (예 : 행 선택 확인란이있는 그리드).

DELETE /messages
[{id:1, version:2},
{id:99, version:3}]
204 No Content

각 메시지에는 고유 한 버전이 있습니다. 여러 헤더를 사용하여 여러 버전을 지정할 수도 있지만 George가 더 간단하고 편리합니다.

이것은 Tomcat (7.0.52) 및 Spring MVC (4.05)에서 작동하며 이전 버전에서도 가능합니다.

@RestController
public class TestController {

    @RequestMapping(value="/echo-delete", method = RequestMethod.DELETE)
    SomeBean echoDelete(@RequestBody SomeBean someBean) {
        return someBean;
    }
}

15
GET (및 DELETE)에 본문이 있으면 HTTP 및 REST가 명확하게 왜곡됩니다. 동시성 제어를 처리하기위한 다른 메커니즘이 있습니다 (예 : If-Modified-Since 및 etag).
브루노

19
스펙이 DELETE에서 본문을 금지하지 않을 때 어떻게 명확하게 잘못 판단합니까?
Neil McGuigan

5
당신은 몸으로 아무것도하지 않기 때문에. 참조 : stackoverflow.com/a/983458/372643
Bruno

14
이것은 정확히 같은 문제입니다. GET을 사용하면 URI로 식별 된 리소스의 표현을 검색 할 수 있으며 DELETE는 URI로 식별 된 리소스를 삭제합니다. 특정 버전을 삭제하려면 다른 버전에 다른 URI를 사용하십시오. URI는 HTTP / REST에서 리소스의 유일한 식별자 여야합니다. 동시성을 처리해야하는 경우 헤더에 메타 데이터를 사용하십시오 (예 : If-Unmodified-Since또는 Etag).
Bruno

5
본문의 버전 필드 대신 ETag 헤더를 사용하십시오
malhal

26

RFC 2616 이 이것을 지정하지 않은 것으로 보입니다 .

섹션 4.3에서 :

요청에 메시지 본문이 존재한다는 것은 요청의 메시지 헤더에 Content-Length 또는 Transfer-Encoding 헤더 필드를 포함시킴으로써 알 수 있습니다. 요청 방법 (5.1.1 절)의 명세가 엔티티 본문을 요청으로 전송하는 것을 허용하지 않는다면, 메시지 본문은 요청에 포함되어서는 안된다 (MUST NOT). 서버는 요청시 메시지 본문을 읽고 전달해야합니다. 요청 방법에 엔티티 본문에 대해 정의 된 의미가 포함되어 있지 않으면 요청을 처리 할 때 메시지 본문을 무시해야합니다.

섹션 9.7 :

DELETE 메소드는 오리진 서버가 Request-URI로 식별 된 자원을 삭제하도록 요청합니다. 이 방법은 오리진 서버에서 사람의 개입 (또는 다른 수단)에 의해 무시 될 수 있습니다. 오리진 서버에서 리턴 된 상태 코드가 조치가 완료되었음을 표시하더라도 클라이언트는 조작이 수행되었음을 보증 할 수 없습니다. 그러나 서버는 응답이 제공 될 때 리소스를 삭제하거나 액세스 할 수없는 위치로 이동시키지 않는 한 성공을 나타내서는 안됩니다.

응답에 상태를 설명하는 엔터티가 포함 된 경우 성공적인 응답은 200 (OK)이고, 조치가 아직 시행되지 않은 경우 202 (Accepted), 조치가 시행되었지만 응답이 포함되지 않은 경우 204 (No Content) 여야합니다. 실체.

요청이 캐시를 통과하고 Request-URI가 현재 캐시 된 하나 이상의 엔티티를 식별하는 경우 해당 항목은 오래된 것으로 취급해야합니다. 이 방법에 대한 응답은 캐시 할 수 없습니다 .c

따라서 명시 적으로 허용되거나 허용되지 않으며, 진행중인 프록시가 메시지 본문을 제거 할 가능성이 있습니다 (읽고 전달해야하지만).


19

DELETE 요청에 본문을 제공하고 Google 클라우드 HTTPS로드 밸런서를 사용하는 경우 400 오류로 요청이 거부됩니다. 나는 벽에 머리를 대고 있었고, 구글은 어떤 이유로 든 몸에 대한 삭제 요청이 잘못된 요청이라고 생각했다.


1
for whatever reason-스펙이 그렇게
말했기

20
이 스펙은 단지 본문이 구체적으로 정의되지 않았다고 말합니다. 정의되어 있지 않고 무시하고 싶다면 시원하게 진행하십시오. 무시하십시오. 그러나 요청을 완전히 거부하는 것은 극단적이고 불필요합니다.
벤 프라이드

1
정의되지 않은 동작에 의존하지 마십시오. 매우 일반적인 모범 사례입니다.
Evert

@ Evert 명시 적으로 정의되지 않은 동작 (예 : C 언어 사양에서 설명하는 것처럼)이 허용되지만 간단하게 설명되지 않은 동작이 있습니다. 메시지 본문을 사용하는 DELETE것이 후자입니다.
Alnitak

9

버전 3.0에 대한 OpenAPI 사양은 본문과 함께 DELETE 메소드에 대한 지원을 중단했음을 주목할 가치가 있습니다.

참조 여기여기에 참조를

이는 향후 구현, 문서화 또는 이러한 API 사용에 영향을 줄 수 있습니다.


7

ElasticSearch가 다음을 사용하는 것 같습니다. https://www.elastic.co/guide/en/elasticsearch/reference/5.x/search-request-scroll.html#_clear_scroll_api

Netty가이를 지원한다는 의미입니다.

의견에서 언급했듯이 더 이상 그렇지 않을 수 있습니다.


1
아파치 http 클라이언트를 사용하는 경우 HttpEntityEnclosingRequestBase를 확장하고 getMethod () 메소드가 GET 또는 DELETE를 리턴하도록하여 자체 버전의 GET 및 DELETE를 쉽게 작성할 수 있습니다. 우리는 elasticsearch와 대화하기 위해 이것을 사용합니다.
Jilles van Gurp

2
죽은 링크-좋아. 우리는 더 많은 사람들 링크 답변의 필요 -하지
cottton

3
링크 된 문서는 이제 POST 요청 만 포함하고 DELETE는 포함하지 않습니다. 이 답변에 메모를 추가 할 가치가 있습니까?
dshepherd

Elasticsearch는 GET 요청과 함께 본문도 사용합니다.
Nidhin David

7

HTTP 메일 링리스트의 Roy Fielding은 http 메일 링리스트 https://lists.w3.org/Archives/Public/ietf-http-wg/2020JanMar/0123.html에 다음 과 같이 명시되어 있습니다 .

GET / DELETE 본문은 요청의 처리 또는 해석에 영향을 미치는 것이 절대적으로 금지되어 있습니다.

이것은 본문이 서버의 동작을 수정해서는 안됨을 의미합니다. 그런 다음 그는 다음을 추가합니다.

메시지 프레이밍을 유지하기 위해 수신 된 바이트를 읽고 버릴 필요가 없습니다.

그리고 마지막으로 시체를 금지하지 않는 이유는 다음과 같습니다.

우리가 본문을 보내는 것을 금지하지 않은 유일한 이유는 본문이 전송되지 않는다고 가정하는 게으른 구현으로 이어질 수 있기 때문입니다.

따라서 클라이언트는 페이로드 본문을 보낼 수 있지만 서버는이를 삭제해야하고 API는 해당 요청에서 페이로드 본문의 의미를 정의하지 않아야합니다.



5

본문과 함께 DELETE를 사용하는 것은 위험합니다 ... REST보다 목록 작업 에이 방법을 선호합니다.

정기 운영

GET / objects / 모든 객체를 얻습니다

GET / 개체 / ID 지정된 ID를 가진 개체를 가져옵니다.

POST / objects 객체를 추가합니다

PUT / object / ID 지정된 ID의 객체를 추가하고 객체를 업데이트합니다

DELETE / object / ID 지정된 ID를 가진 개체를 삭제합니다.

모든 사용자 지정 작업은 POST입니다

POST / objects / addList 본문에 포함 된 객체의 목록 또는 배열을 추가합니다

POST / objects / deleteList 본문에 포함 된 객체 목록을 삭제합니다.

POST / objects / customQuery 본문의 사용자 지정 쿼리를 기반으로 목록을 만듭니다.

클라이언트가 확장 작업을 지원하지 않으면 정기적으로 작동 할 수 있습니다.


POSTPOST 응답의 의미가 명확하지 않기 때문에, 특히 Location 헤더와 관련 하여 a를 사용하는 것은 새로운 리소스를 만드는 데 RESTA 한 방법이 아닙니다. 본질적으로 HTTP를 남겨두고 RPC를 맨 위에 둡니다. 올바른 "HTTP / REST 방식"은 헤더를 사용하여 자원을 작성 PUT하는 것입니다 If-None-Match: *(또는 적절한 HTTP 메소드 지정, MKCOL기타 참조 ).
hnh

4

기존 답변에 대한 많은 의견이 있었지만 이것에 대한 좋은 답변이 게시되지 않았다고 생각합니다. 나는 그 의견의 요지를 새로운 답변으로 들어 올릴 것입니다.

RFC7231의이 단락은 몇 번 인용되어 요약됩니다.

DELETE 요청 메시지 내의 페이로드에는 정의 된 의미가 없습니다. DELETE 요청에서 페이로드 본문을 전송하면 일부 기존 구현에서 요청을 거부 할 수 있습니다.

다른 답변에서 놓친 것은 그 의미입니다. 예 DELETE, 요청시 본문을 포함 할 수 있지만 의미 상 의미가 없습니다. 이것이 실제로 의미하는 것은 DELETE요청 본문 으로 요청 을 발행하는 것이 의미 적으로 요청 본문을 포함하지 않는 것과 같습니다.

요청 본문을 포함하면 요청에 영향을 미치지 않아야하므로 요청을 포함시킬 필요가 없습니다.

tl; dr : 기술적으로 DELETE요청 본문이있는 요청은 허용되지만 그렇게하는 것은 결코 유용하지 않습니다.


2
"의미 적으로 의미가 없음"은 "정의 된 의미가 없음"과 같은 의미가 아닙니다. 전자는 의미를 가질 수 없음 을 의미합니다. 후자는 RFC 자체가 그 의미가 무엇인지 명시하지 않는다는 것을 의미합니다. (RFC 작성)
Alnitak

1
즉, API 구현자가 자체적으로 의미를 정의하려는 경우 완벽하게 자유롭게 할 수 있습니다.
Alnitak

1
@Alnitak 이것은 분명히 잘못된 해석입니다. 이 정의에 따르면 모든 HTTP 요청 본문에는 정의 된 시맨틱이 없지만 DELETE 및 GET은 사양에서 구체적으로 호출됩니다. 다음은 아직 출판되지 않은 초안에서 GET 요청에 대해 구체적으로 언급 한 스 니펫입니다.
Evert

1
나는 현재 발표 된 RFC에서 이것이 확실하지 않다는 것에 동의하지 않지만, 당신이 나를 믿지 않는다면 저자에게 DELETE와 GET에 대한 의도를 묻도록 권유합니다. 내 대답과 일치한다는 것을 알 수 있습니다. 여러분과 마찬가지로 저는 표준기구에도 참여하고 있으며 RFC 해석 방법에 대한 의견을 가진 고독한 사람이 아닙니다.
Evert

2
그렇다면 7231의 말이 잘못되었으므로 "페이로드 바디를 무시해야합니다"라고 말해야합니다. 위에서 언급 한 초안은 무엇입니까?
Alnitak

3

이 문제 테스트에 참여한 사람이있는 경우 아니요. 보편적으로 지원되지 않습니다.

나는 현재 Sahi Pro로 테스트 중이며 http DELETE 호출은 제공된 바디 데이터 (끝점 디자인에 따라 대량으로 삭제되는 많은 ID 목록)를 제거합니다.

나는 그들과 여러 번 접촉을했고 검토 할 수 있도록 스크립, 이미지, 로그의 세 가지 개별 패키지로 보냈지 만 여전히 이것을 확인하지 못했습니다. 실패한 패치와 부재중 전화 회의는 나중에 지원을 통해 전화를 걸었지만 여전히 확실한 대답을 얻지 못했습니다.

나는 Sahi가 이것을 지원하지 않는다고 확신하며, 다른 많은 도구가 제품군을 따르는 것을 상상할 것입니다.


최신 버전의 Sahi Pro에서 구현됩니다. Sahi는 java를 사용하여 HTTP 호출을 수행하므로 Java는 버전 1.8 이전의 버그로 인해 사용자가 DELETE 요청을 할 수 없습니다. 따라서 Java 1.8 이상과 Sahi Pro 6.1.1 (곧 공개 예정)을 통해 사람들은 Sahi에서 body와 함께 DELETE 요청을 할 수 있습니다.
Vivek V Dwivedi

-1

아래 GitHUb URL이 도움이 될 것입니다. 실제로 Tomcat과 같은 Application Server는 Weblogic에서 요청 페이로드로 HTTP.DELETE 호출을 거부합니다. 이 모든 것을 명심하고 github에 예제를 추가했습니다.

https://github.com/ashish720/spring-examples


-1

요청 본문으로 DELETE 작업을 구현할 수있었습니다. AWS Lambda 및 AWS API 게이트웨이를 사용하고 Go 언어를 사용했습니다.


3
그들은 능력이 아니라 표준에 대해 이야기하고 있습니다. 당신은 몸에 GET 요청을 할 수 있습니다, 그것은 좋지 않습니다
ReZa
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.