요청 본문이있는 HTTP GET


2109

우리 응용 프로그램을 위해 새로운 RESTful 웹 서비스를 개발 중입니다.

특정 엔티티에서 GET을 수행 할 때 클라이언트는 엔티티의 컨텐츠를 요청할 수 있습니다. 목록 정렬과 같은 일부 매개 변수를 추가하려는 경우 쿼리 문자열에 이러한 매개 변수를 추가 할 수 있습니다.

또는 사람들이 요청 본문에서 이러한 매개 변수를 지정할 수 있기를 바랍니다. HTTP / 1.1 은 이것을 명시 적으로 금지하지 않는 것 같습니다. 이를 통해 더 많은 정보를 지정할 수 있으며 복잡한 XML 요청을보다 쉽게 ​​지정할 수 있습니다.

내 질문 :

  • 이것이 좋은 생각입니까?
  • HTTP 클라이언트는 GET 요청 내에서 요청 본문 사용에 문제가 있습니까?

http://tools.ietf.org/html/rfc2616


552
XML 또는 JSON 요청 본문을 쉽게 전송할 수 있다는 장점이 있으며 길이 제한이 없으며 인코딩하기가 더 쉽습니다 (UTF-8).
Evert

29
요청 본문을 허용하는 안전하고 dem 등한 방법 인 경우 SEARCH, PROPFIND 및 REPORT를 볼 수 있습니다. 물론 GET을 사용하지 않고 요청 본문이 있으면 캐싱이 어느 정도 커집니다.
Julian Reschke

226
@fijiaaron : 3 년이 지난 후 웹 서비스를 작성하면서 광범위한 경험을 쌓았습니다. 기본적으로 지난 몇 년 동안 내가 한 모든 일입니다. GET 요청에 본문을 추가하는 것은 실제로 나쁜 생각입니다. 상위 2 개의 답변은 바위처럼 서 있습니다.
08:31에 Evert

26
@Ellesedil : 간단히 말해서 : POST를 통해 GET을 사용할 때의 장점은 HTTP 설계 방식으로 인해 존재합니다. 이러한 방식으로 표준을 위반하면 이러한 이점이 더 이상 존재하지 않습니다. 따라서 POST : Aesthetics 대신 GET + 요청 본문을 사용해야하는 이유는 하나뿐입니다. 미학보다 견고한 디자인을 희생하지 마십시오.
에버트

7
Evert가 말한 내용에 밑줄을 긋기 위해 : "길이 제한이 없습니다". 쿼리 매개 변수가있는 GET이 길이 제한 (2048)을 초과하는 경우 쿼리 문자열 정보를 json 객체 (예 : 요청 본문)에 넣는 것 이외의 다른 선택이 있습니다.
키어런 라이언

답변:


1724

GET 요청에 바디를 포함시키는 것에 대한 Roy Fielding의 의견 .

예. 다시 말해, 모든 HTTP 요청 메시지는 메시지 본문을 포함 할 수 있으므로이를 염두에두고 메시지를 구문 분석해야합니다. 그러나 GET에 대한 서버 시맨틱은 본문에 요청에 대한 시맨틱 의미가 없도록 제한됩니다. 구문 분석에 대한 요구 사항은 메소드 시맨틱에 대한 요구 사항과 별개입니다.

따라서 그렇습니다. GET을 사용하여 본문을 보낼 수 있으며, 그렇게하는 것은 결코 유용하지 않습니다.

이것은 사양이 분할되면 (작업 진행 중) 다시 명확 해 지도록 HTTP / 1.1의 계층화 된 디자인의 일부입니다.

.... 로이

예, GET을 사용하여 요청 본문을 보낼 수 있지만 의미가 없습니다. 서버에서 구문 분석 하고 내용에 따라 응답을 변경하여 의미를 부여 하면 HTTP / 1.1 스펙 4.3 절 에서이 권장 사항을 무시하는 것입니다 .

[...] 요청 방법 엔티티 바디에 대해 정의 된 의미를 포함하지 않는 경우, 메시지 본문 SHOULD 요청을 처리 할 때 무시된다.

HTTP / 1.1 스펙 섹션 9.3 에서 GET 메소드에 대한 설명은 다음과 같습니다.

GET 메소드는 Request-URI로 식별 된 모든 정보 ([...])를 검색하는 것을 의미합니다.

이것은 요청 본문이 GET 요청에서 자원 식별의 일부가 아니라 요청 URI만을 나타냅니다.

업데이트 "HTTP / 1.1 사양"으로 참조 된 RFC2616은 이제 더 이상 사용되지 않습니다. 2014 년에는 RFC 7230-7237로 대체되었습니다. "요청을 처리 할 때 메시지 본문을 무시해야합니다"라는 인용문이 삭제되었습니다. "메시지 본문에 대한 용도를 정의하지 않더라도 요청 메시지 프레임은 메소드 시맨틱과 무관합니다." 삭제되었습니다. -댓글에서


71
캐싱 / 프록시는 여러분이 깨뜨릴 가능성이 가장 높은 두 가지입니다. "시맨틱"은 "다른 구성 요소를 만드는 사람들이 다른 구성 요소가 작동 할 것으로 기대하는 방식"을 말하는 또 다른 방법입니다. 시맨틱을 위반하면 사람들이 그 시맨틱을 존중할 것으로 예상되는 것을 쓴 곳에서 문제가 발생할 가능성이 더 높습니다.
스튜어트 P. 벤틀리

108
Elasticsearch는 GET에서 HTTP 요청 본문을 활용하는 상당히 중요한 제품입니다. 매뉴얼에 따르면 HTTP 요청이 본문을 지원 해야하는지 여부는 정의되어 있지 않습니다. 나는 개인적으로 GET 요청 본문을 채우는 것에 익숙하지 않지만, 의견이 다른 것 같고 그들이하는 일을 알아야합니다. elastic.co/guide/en/elasticsearch/guide/current/…
GordonM

25
GET 요청 본문을 의미하는 @iwein은 실제로 사양을 위반 하지 않습니다 . HTTP / 1.1 은 서버가 본문 을 무시하도록 지정해야 하지만 RFC 2119 는 구현자가 "SHOULD"절을 무시해야 할 이유가있는 경우이를 무시할 수 있도록 지정합니다. 오히려 클라이언트 GET 본문을 변경해도 응답이 변경 되지 않는다고 가정하면 사양을 위반합니다 .
Emil Lundberg

107
"HTTP / 1.1 스펙"으로 참조 된 RFC2616은 이제 더 이상 사용되지 않습니다. 2014 년에는 RFC 7230-7237로 대체되었습니다. " 요청을 처리 할 때 메시지 본문을 무시해야합니다 " 라는 인용문 이 삭제되었습니다 . 그냥 "지금의 방법이 메시지 본문에 대한 사용을 정의하지 않는 경우에도 요청 메시지 프레임은, 방법 의미의 독립적 인 제 2 회 따옴표" " 수단은 어떤 정보 검색 GET 메서드를 Request-URI가 식별하는 ... " 한 삭제 . 그래서 나는 편집에 응답 @Jarl을 제안
아르 템 Nakonechny

28
나는 그것이 오래된 실이라는 것을 알고 있습니다. @Artem Nakonechny는 기술적으로는 맞지만 새로운 사양에 따르면 "GET 요청 메시지 내의 페이로드에 정의 된 의미가 없습니다. GET 요청에 페이로드 본문을 보내면 일부 기존 구현에서 요청을 거부 할 수 있습니다." 따라서 피할 수 있다면 여전히 좋은 생각은 아닙니다.
fastcatch

289

HTTP 사양에서 명시 적으로 배제하지 않는 한 그렇게 할 는 있지만 사람들이 그런 식으로 작동하지 않기 때문에 단순히 피하는 것이 좋습니다. HTTP 요청 체인에는 여러 단계가 있으며, HTTP 요청 체인은 "대부분"HTTP 사양을 준수하지만, 웹 브라우저에서 전통적으로 사용되는 것처럼 동작한다는 것뿐입니다. (투명한 프록시, 가속기, A / V 툴킷 등을 생각하고 있습니다.)

이것은 견고성 원칙의 배후에있는 대략적인 것입니다. "당신이 받아들이는 것에서 자유롭고, 당신이 보내는 것에서 보수적이어야합니다."

그러나 그럴만한 이유가 있다면 그렇게하십시오.


228
견고성 원칙에 결함이 있습니다. 당신이 받아들이는 것에 자유 주의적이라면, 당신이 쓰레기를 받아들이 기 때문에 입양의 측면에서 성공하면 쓰레기를 얻게 될 것입니다. 인터페이스를 발전시키기가 더 어려워 질 것입니다. HTML을보십시오. 그것이 행동에있어서의 중상 원리입니다.
Eugene Beresovsky 1

27
프로토콜의 채택과 남용의 성공과 폭은 견고성 원칙의 가치에 달려 있다고 생각합니다.
caskey

39
실제 HTML 파싱을 시도한 적이 있습니까? Google (Chrome) 및 Apple (Safari)과 같은 큰 플레이어를 포함하여 거의 모든 사람들이 기존 구현에 의존했지만 결국 KDE의 KHTML에 의존했습니다. 그 재사용은 물론 훌륭하지만 .net 응용 프로그램에서 html을 표시 해 보셨습니까? 문제 및 충돌과 함께 관리되지 않는 IE (또는 유사한) 구성 요소를 포함하거나 텍스트를 선택할 수없는 사용 가능한 (codeplex) 관리되는 구성 요소를 사용해야하므로 악몽입니다.
Eugene Beresovsky

6
HTTP 사양은 GET 요청이있는 본문 데이터를 허용 할뿐만 아니라 일반적인 관행이기도합니다. 널리 사용되는 ElasticSearch 엔진의 _search API는 JSON 본문에 쿼리가 첨부 된 GET 요청을 권장합니다. 불완전한 HTTP 클라이언트 구현에 대한 양보로 POST 요청도 허용합니다.
Christian Pietsch

3
@ChristianPietsch, 오늘은 일반적인 관행입니다. 4 년 전에는 그렇지 않았습니다. 스펙은 클라이언트가 요청에 엔티티를 선택적으로 포함 (MAY) 할 수 있지만 (섹션 7), MAY의 의미는 RFC2119에 정의되어 있으며 (크 래피) 프록시 서버는 스펙을 준수 할 수 있으며 GET 요청에서 엔티티를 제거 할 수 있습니다. 특히 충돌하지 않는 한 포함 된 엔티티가 아닌 요청 헤더를 전달하여 '기능 저하'를 제공 할 수 있습니다. 마찬가지로, 다른 프로토콜 레벨 사이에서 프록시 할 때 버전 변경이 반드시 수행되어야하는 규칙에 대한 많은 규칙이 있습니다.
caskey 2016 년

151

캐싱을 활용하려고하면 문제가 발생할 수 있습니다. 프록시는 매개 변수가 응답에 영향을 미치는지 확인하기 위해 GET 본문을 보지 않습니다.


10
ETag / Last-Modified 헤더 필드를 사용하면 다음과 같은 방식으로 도움이됩니다. "조건부 GET"을 사용하는 경우 프록시 / 캐시가이 정보에 대해 작동 할 수 있습니다.
jldupont

2
@jldupont 캐시는 유효성 검사기의 존재를 사용하여 오래된 응답의 유효성을 다시 확인할 수 있는지 확인하지만 기본 캐시 키 또는 보조 캐시 키의 일부로 사용되지는 않습니다.
Darrel Miller

쿼리 매개 변수에서 본문의 체크섬으로 문제를 해결할 수 있습니다
Adrian May

73

어느 위해 RESTClient 이나 REST 콘솔은 이 기능을 지원하지만 컬을 수행합니다.

HTTP 사양은 4.3 절에 말한다

요청 방법 (5.1.1 절)의 명세가 엔티티 본문을 요청으로 전송하는 것을 허용하지 않는다면, 메시지 본문은 요청에 포함되어서는 안된다 (MUST NOT).

섹션 5.1.1 은 다양한 방법에 대해 섹션 9.x로 리디렉션합니다. 이들 중 어느 것도 메시지 본문의 포함을 명시 적으로 금지하지 않습니다. 하나...

섹션 5.2에 따르면

인터넷 요청으로 식별 된 정확한 리소스는 Request-URI와 Host header 필드를 모두 검사하여 결정됩니다.

9.3 절은 말한다

GET 메소드는 Request-URI에 의해 식별되는 모든 정보 (엔터티 형태)를 검색하는 것을 의미합니다.

GET 요청을 처리 할 때 서버는 Request-URI 및 Host 헤더 필드 이외의 다른 것을 검사 할 필요 가 없음을 함께 제안 합니다.

요약하면 HTTP 사양은 GET을 사용하여 메시지 본문을 보내지 못하게하지는 않지만 모든 서버에서 지원하지 않는 경우 놀라지 않을 정도로 모호합니다.


2
Paw에는 본문이있는 GET 요청을 지원하는 옵션도 있지만 설정에서 활성화해야합니다.
s.Daniel

"GET 방법은 Request-URI에 의해 식별되는 모든 정보 (엔터티 형태)를 검색하는 것을 의미합니다." 그렇다면 모든 엔티티를 얻는 GET 엔드 ​​포인트를 갖는 것이 기술적으로 불법적입니까? 예를 GET /contacts/100/addresses들어을 가진 사람의 주소 모음을 반환합니다 id=100.
Josh M.

REST API 테스트를위한 나머지 확실한 Java 라이브러리는 본문과 함께 GET 요청을 지원하지 않습니다. Apache HttpClient도 지원하지 않습니다.
Paulo Merson

Django는 GET 본문 파싱을 지원합니다
Bruno Finger

60

Elasticsearch는 본문이있는 GET 요청을 수락합니다. 이것이 바람직한 방법 인 것 같습니다. Elasticsearch 안내서

Ruby 드라이버와 같은 일부 클라이언트 라이브러리는 개발 모드에서 cry 명령을 stdout에 기록 할 수 있으며이 구문을 광범위하게 사용합니다.


5
Elasticsearch가 왜 이것을 허용하는지 궁금합니다. 즉, GET 요청에 페이로드가있는 모든 문서를 계산하는이 쿼리 curl -XGET 'http://localhost:9200/_count?pretty' -d ' { "query": { "match_all": {} } }' 는 페이로드를 source매개 변수 로 포함하는 것과 같습니다 . curl -XGET 'http://localhost:9200/_count?pretty&source=%7B%22query%22%3A%7B%22match_all%22%3A%7B%7D%7D%7D'
arun

40
복잡한 쿼리는 http 헤더 최대 길이에 도달 할 수 있습니다.
s.Daniel

11
그것은 몸을 포함하는 것은 나쁜 습관으로 간주된다고 생각
하면서이

1
복잡한 쿼리 일 필요조차 없습니다. 간단한 스크롤조차도 매우 긴 scroll_id (샤드가 많은 클러스터에서)를 반환 할 수 있으며 거기에 추가하면 최대 URL 길이가 초과됩니다.
Brent Hronik

11
Elasticsearch는 POST를 사용한 동일한 요청을 지원합니다. 그들은 데이터를 쿼리 할 때 GET이 POST보다 의미 론적으로 정확하다고 느꼈기 때문에 GET에 본문을 허용하기로 선택했습니다. 이 스레드에서 Elasticsearch가 너무 많이 언급되어 있다는 것은 재밌습니다. 연습을 따라야 할 이유 중 하나로 (인기있는 제품이더라도) 한 가지 예를 사용하지 않을 것입니다.
DSO

32

달성하려는 것은 훨씬 일반적인 방법과 GET과 함께 페이로드를 사용하지 않는 방법으로 오랫동안 수행되었습니다.

특정 검색 미디어 유형을 구축하거나 더 RESTful하고 싶다면 OpenSearch와 같은 것을 사용하고 서버가 지시 한 URI에 요청을 POST하십시오 (예 : / search). 그런 다음 서버는 검색 결과를 생성하거나 최종 URI를 빌드하고 303을 사용하여 리디렉션 할 수 있습니다.

이것은 전통적인 PRG 방법을 따르는 장점이 있으며 캐시 중개인이 결과를 캐시하는 데 도움이됩니다.

즉, URI는 ASCII가 아닌 모든 항목에 대해 인코딩되므로 application / x-www-form-urlencoded 및 multipart / form-data입니다. ReSTful 시나리오를 지원하려는 경우 또 다른 사용자 정의 json 형식을 작성하는 대신 이것을 사용하는 것이 좋습니다.


4
특정 검색 미디어 유형을 간단하게 구축 할 수 있습니다.
Piotr Dobrogost

2
이것으로 application / vnd.myCompany.search + json이라는 미디어 유형을 생성하여 클라이언트가 발행하려는 검색 템플릿 종류를 포함 할 수 있으며 클라이언트는이를 POST로 보낼 수 있습니다. 강조한 것처럼 이미 해당 미디어 유형이 있으며이를 OpenSearch라고하며 기존 표준으로 시나리오를 구현할 수있을 때 사용자 지정 경로에서 기존 미디어 유형을 재사용해야합니다.
SerialSeb

14
그것은 영리하지만 지나치게 복잡하고 비효율적입니다. 이제 검색 기준으로 POST를 전송하고 POST에서 URI로 응답으로 URI를 가져온 다음 검색 기준 URI가 포함 된 GET을 서버로 보내서 기준을 GET으로 보내 결과를 다시 보내야합니다. (URI에 URI를 포함시키는 것은 기술적으로 불가능합니다. 255자를 넘을 수없는 내용으로 최대 255 자까지 보낼 수 없기 때문에 부분 식별자와 서버를 사용해야합니다.
POSTed

29

몸과 함께 GET을 보내거나 POST를 보내고 RESTish religiosity를 포기할 수 있습니다.

훌륭한 결정도 아니지만 GET 본문을 전송하면 일부 클라이언트 및 일부 서버의 문제를 방지 할 수 있습니다.

POST를 수행하면 일부 RESTish 프레임 워크에 장애물이있을 수 있습니다.

Julian Reschke는 위의 "SEARCH"와 같은 비표준 HTTP 헤더를 사용하여 제안했을 때 지원할 가능성이 적다는 점을 제외하고는 훌륭한 해결책이 될 수 있다고 제안했습니다.

위의 각 작업을 수행 할 수 있고 수행 할 수없는 클라이언트를 나열하는 것이 가장 생산적 일 수 있습니다.

본문과 함께 GET을 보낼 수없는 고객 (내가 아는 것) :

  • XmlHTTPRequest 피들러

본문과 함께 GET을 보낼 수있는 클라이언트 :

  • 대부분의 브라우저

GET에서 본문을 검색 할 수있는 서버 및 라이브러리 :

  • 아파치
  • PHP

GET에서 본문을 제거하는 서버 (및 프록시) :

  • ?

2
Squid 3.1.6은 또한 Content-Length가 0이거나 설정되지 않은 경우 GET 본문을 제거하고 그렇지 않으면 길이가 설정되어 있어도 HTTP 411 길이를 다시 보냅니다.
rkok

2
피들러는 의지하지만 경고합니다.
toddmo

SEARCH방법이 길을 잃을 수도 있다고 말하고 있습니까? 프록시가 방법을 이해하지 못하는 경우, 방법을 그대로 전달해야하므로 왜이 방법이 고장날 것이라고 생각하는지 잘 모르겠습니다.
Alexis Wilke

22

이 질문을 IETF HTTP WG에 넣었습니다. Roy Fielding (1998 년 http / 1.1 문서 저자)의 의견은

"... 수신되면 해당 본문을 구문 분석하고 삭제하는 것 이외의 다른 작업을 수행하기 위해 구현이 중단됩니다.

RFC 7213 (HTTPbis) 상태 :

"GET 요청 메시지 내의 페이로드에는 정의 된 의미가 없습니다."

의도는 GET 요청 본문에 의미 론적 의미가 금지되어 있기 때문에 요청 본문을 사용하여 결과에 영향을 줄 수 없음을 의미합니다.

GET에 본문을 포함하면 다양한 방법으로 요청을 확실히 중단 시키는 프록시가 있습니다 .

요약하면 그렇게하지 마십시오.


21

어느 서버가이를 무시합니까? – fijiaaron 8 월 30 일 12시 21 분 27 초

구글 예를 들어 그것을 무시보다 더하고있다, 그것은 그것에게 고려하게됩니다 오류 !

간단한 netcat으로 직접 시도해보십시오.

$ netcat www.google.com 80
GET / HTTP/1.1
Host: www.google.com
Content-length: 6

1234

(1234 내용 뒤에 CR-LF가옵니다. 총 6 바이트입니다)

그리고 당신은 얻을 것이다 :

HTTP/1.1 400 Bad Request
Server: GFE/2.0
(....)
Error 400 (Bad Request)
400. That’s an error.
Your client has issued a malformed or illegal request. That’s all we know.

또한 AkamaiGhost가 제공하는 Bing, Apple 등으로부터 400 건의 Bad Request를받습니다.

따라서 본문 엔터티와 함께 ​​GET 요청을 사용하지 않는 것이 좋습니다.


65
이 예제는 일반적으로 사람들이 GET요청 에 본문을 추가 할 때 자체 사용자 정의 서버가이를 처리 할 수 ​​있기 때문에 의미가 없습니다. 따라서 다른 "이동 부품"(브라우저, 캐시 등)이 제대로 작동하는지 여부가 문제입니다.
Pacerier

6
페이로드가 GET 특정 엔드 포인트에서 예상되지 않거나 합리적이지 않기 때문에 이는 잘못된 요청 GET입니다. 일반적인 경우 에는 사용하지 않습니다 . 임의의 페이로드 는 내용이 특정 요청의 맥락에서 이해하기 POST쉬운 400 Bad Request형식이 아닌 경우 와 마찬가지로 쉽게 중단 되어 동일한 내용을 반환 할 수 있습니다 .
nobar

그리고 엔드 포인트 전체뿐만 아니라 특정 URL에도 적용 됩니다.
Lawrence Dol 2019

1
해당 URL에서 Google의 서버 구현이기 때문에 관련이 없습니다. 따라서 질문에는 이치에
Joel Duckworth

나를 위해 get request + body와 함께 firebase 함수를 사용하려고 시도했기 때문에 유용 했으며이 오류는 매우 암호가 많고 이해하기 어려울 수 있습니다.
scrimau

19

에서 RFC 2616, 섹션 4.3 , "메시지 본문"

서버는 요청시 메시지 본문을 읽고 전달해야합니다. 요청 방법에 엔티티 본문에 대해 정의 된 의미가 포함되어 있지 않으면 요청을 처리 할 때 메시지 본문을 무시해야합니다.

즉, 서버는 항상 네트워크에서 제공된 요청 본문을 읽어야합니다 (Content-Length 확인 또는 청크 본문 읽기 등). 또한 프록시는 그러한 요청 본문을 전달해야합니다. 그런 다음 RFC가 지정된 메소드의 본문에 대한 의미를 정의하면 서버는 실제로 요청 본문을 사용하여 응답을 생성 할 수 있습니다. 그러나 RFC 본문에 대한 의미를 정의 하지 않으면 서버는이를 무시해야합니다.

이것은 위의 Fielding의 인용문과 일치합니다.

9.3 절 . "GET"은 GET 메소드의 의미론을 설명하고 요청 본문은 언급하지 않습니다. 따라서 서버는 GET 요청에서 수신 한 요청 본문을 무시해야합니다.


섹션 9.5 , "POST"에도 요청 본문이 언급되어 있지 않으므로이 논리에 결함이 있습니다.
CarLuva 2016 년

9
@CarLuva POST 섹션에 "POST 메서드는 원본 서버가 엔클로저에 포함 된 엔터티를 수락하도록 요청하는 데 사용됩니다 ..." 라고 말합니다 . 엔터티 본문 섹션에는 "엔터티 본문이 메시지 본문에서 가져옵니다 ..." POST 섹션은 메시지 본문을 언급하지만 POST 요청의 메시지 본문이 전달하는 엔티티 본문을 간접적으로 참조합니다.
frederickf

9

XMLHttpRequest에 따르면 유효하지 않습니다. 로부터 표준 :

4.5.6 send()방법

client . send([body = null])

요청을 시작합니다. 선택적 인수는 요청 본문을 제공합니다. request 메소드가 GET또는 이면 인수가 무시됩니다 HEAD.

InvalidStateError상태가 열리지 않거나 send()플래그가 설정된 경우 예외를 발생 시킵니다.

방법은 다음 단계를 실행해야합니다 :send(body)

  1. 상태가되지 않으면 , 던져 InvalidStateError예외.
  2. 는 IF send()플래그가 설정되어, 던져 InvalidStateError예외.
  3. 요청 메소드가 GET또는 인 HEAD경우 body 를 null로 설정하십시오 .
  4. body 가 널인 경우 다음 단계로 이동하십시오.

그러나 GET 요청에 큰 본문 내용이 필요할 수 있기 때문에 그렇게 생각하지 않습니다.

따라서 브라우저의 XMLHttpRequest를 사용하면 작동하지 않을 수 있습니다.


1
XMLHttpRequest가 구현이라는 사실로 인해 하향 투표되었습니다. 구현해야하는 실제 사양을 반영하지 않을 수 있습니다.
floum

10
일부 구현에서 GET을 사용하여 본문을 전송하는 것을 지원하지 않으면 사양에 관계없이이를 수행하지 않는 이유 일 수 있습니다. 실제로 작업중 인 크로스 플랫폼 제품 에서이 정확한 문제가 발생했습니다 .XMLHttpRequest를 사용하는 플랫폼 만 get을 보내지 못했습니다.
pjcard

8

캐싱 가능한 JSON / XML 본문을 웹 응용 프로그램으로 보내려면 데이터를 넣을 수있는 유일한 장소는 RFC4648로 인코딩 된 쿼리 문자열 ( URL 및 파일 이름 안전 알파벳을 사용한 Base 64 인코딩)입니다 . 물론 JSON을 urlencode하고 URL 매개 변수의 값에 넣을 수는 있지만 Base64는 더 작은 결과를 제공합니다. URL 크기 제한 이 있습니다. 다른 브라우저에서 URL의 최대 길이는 얼마입니까?를 참조하십시오 . .

Base64의 패딩 =문자가 URL의 매개 변수 값에 좋지 않을 수 있다고 생각할 수도 있지만 http://mail.python.org/pipermail/python-bugs-list/2007-February/037195.html 토론을 참조 하십시오 . 그러나 패딩이있는 인코딩 된 문자열은 값이 비어있는 매개 변수 키로 해석되므로 param 이름없이 인코딩 된 데이터를 넣지 마십시오. 나는 같은 것을 사용할 것이다 ?_b64=<encodeddata>.


나는 이것이 매우 나쁜 생각이라고 생각한다 :) 그러나 내가 이런 식으로하려면, 대신 사용자 정의 HTTP 헤더를 사용하고 (항상 Vary를 응답으로 보내야한다).
에버트

나쁘거나 불가능하지만 :) 헤더의 데이터와 관련하여 데이터 크기와 비슷한 문제가 있습니다 . stackoverflow.com/questions/686217/…을 참조하십시오 . 그러나 Vary헤더 를 언급 해 주셔서 감사합니다 . 실제 잠재력을 알지 못했습니다.
gertas

6

나는 이것을 권고하지 않을 것이며, 그것은 표준 관행에 위배되며 그 대가로 그다지 많은 것을 제공하지 않습니다. 옵션이 아닌 컨텐츠를 위해 본문을 유지하려고합니다.


5

부적합한 base64로 인코딩 된 헤더는 어떻습니까? "SOMETHINGAPP-PARAMS : sdfSD45fdg45 / aS"

길이 제한 hm. POST 처리가 의미를 구별하도록 할 수 없습니까? 정렬과 같은 간단한 매개 변수를 원한다면 이것이 왜 문제가되는지 모르겠습니다. 당신이 걱정하는 것이 확실합니다.


x-접두사를 사용하여 원하는 매개 변수를 보낼 수 있습니다. 헤더 길이에 대한 제한은 전적으로 서버 임의 제한입니다.
Chris Marisic 2016 년

4

프로토콜이 OOP를 지원하지 않으므로 REST가 화가 났으며 Get방법은 증거입니다. 솔루션으로 DTO를 JSON으로 직렬화 한 다음 쿼리 문자열을 만들 수 있습니다. 서버 측에서는 쿼리 문자열을 DTO에 직렬화 해제 할 수 있습니다.

살펴보십시오 :

메시지 기반 접근 방식을 사용하면 Get 메소드 제한 사항을 해결할 수 있습니다. 요청 본문과 마찬가지로 모든 DTO를 보낼 수 있습니다

Nelibur 웹 서비스 프레임 워크는 사용할 수있는 기능을 제공합니다

var client = new JsonServiceClient(Settings.Default.ServiceAddress);
var request = new GetClientRequest
    {
        Id = new Guid("2217239b0e-b35b-4d32-95c7-5db43e2bd573")
    };
var response = client.Get<GetClientRequest, ClientResponse>(request);

as you can see, the GetClientRequest was encoded to the following query string

http://localhost/clients/GetWithResponse?type=GetClientRequest&data=%7B%22Id%22:%2217239b0e-b35b-4d32-95c7-5db43e2bd573%22%7D

8
POST 만 사용해야합니다. URL에 메소드 이름이 있으면 기본 나머지 디자인을 위반 한 것입니다. 이것은 RPC입니다. POST를 사용하십시오.
에버트

3
나는 그것이 큰 문제라고 생각하지 않으며 RESTful URL로 개발하는 동안 더 많은 문제가 있습니다 (예 : orders / 1). 나에 관해서는 Get 메소드에 문제가있어 OOP와 호환되지 않습니다. 그리고 누가 URL이 어떻게 생겼는지에 관심이 있습니다 :) 그러나 메시지 기반 접근 방식을 사용하면 안정적인 원격 인터페이스를 만들 수 있으며 실제로 중요합니다. PS는, 그것은 RPC의 아니에요 메시지 기반
GSerjo

3
REST의 요점을 놓친 것 같습니다. 당신이 말할 때, 누가 URL의 모양을 좋아하는지, REST는 잘 신경 쓰입니다. REST가 OOP와 호환되는 이유는 무엇입니까?
shmish111

아니요, 조금만 더 보지 못했습니다
GSerjo

4

예를 들어 Curl, Apache 및 PHP에서 작동합니다.

PHP 파일 :

<?php
echo $_SERVER['REQUEST_METHOD'] . PHP_EOL;
echo file_get_contents('php://input') . PHP_EOL;

콘솔 명령 :

$ curl -X GET -H "Content-Type: application/json" -d '{"the": "body"}' 'http://localhost/test/get.php'

산출:

GET
{"the": "body"}

재미있는 실험! PHP는 $_POST본문이 POST 요청과 함께 전송 될 때만 읽습니다 application/x-www-form-urlencoded. 이는 GET요청 에서 본문이 무시됨을 의미합니다 . 이 경우 : $_GET$_POST정말이 시점에서 어쨌든 오해의 소지가있다. 더 나은 사용php://input
Martin Muzatko

3

IMHO는 JSON인코딩 된 (즉 , encodeURIComponent)을 사양을 URL위반하지 않고 서버로 HTTP가져올 수 있는 방식으로 보낼 수 있습니다 JSON.


28
예, 그러나 가장 큰 문제는 길이 제한입니다. 어떻게 처리합니까?
Sebas

2

GET과 함께 요청 본문을 사용하는 것보다 훨씬 나은 옵션 목록이 있습니다.

각 범주에 대한 범주와 항목이 있다고 가정 해 봅시다. 둘 다 id로 식별됩니다 (이 예에서는 "catid"/ "itemid"). 특정 "순서"에서 다른 매개 변수 "sortby"에 따라 정렬하려고합니다. "정렬"및 "순서"에 대한 매개 변수를 전달하려고합니다.

당신은 할 수 있습니다 :

  1. 쿼리 문자열 사용 example.com/category/{catid}/item/{itemid}?sortby=itemname&order=asc
  2. 경로에 mod_rewrite (또는 이와 유사한)를 사용하십시오. example.com/category/{catid}/item/{itemid}/{sortby}/{order}
  3. 요청과 함께 전달한 개별 HTTP 헤더를 사용하십시오.
  4. POST와 같은 다른 방법을 사용하여 리소스를 검색하십시오.

모두 단점이 있지만 몸에 GET을 사용하는 것보다 훨씬 낫습니다.


0

이 페이지에서 자주 인용되는 것처럼 인기있는 도구가 이것을 사용하더라도 사양에 의해 금지되지는 않지만 너무 이국적이라는 것은 여전히 ​​나쁜 생각이라고 생각합니다.

많은 중간 인프라가 그러한 요청을 거부 할 수 있습니다.

예를 들어으로이 같은 웹 사이트의 앞에 가능한 CDN의 일부를 사용하여 잊어 :

뷰어 GET요청에 본문이 포함 된 경우 CloudFront는 HTTP 상태 코드 403 (Forbidden)을 뷰어에 반환합니다.

그리고 네, 귀하의 클라이언트 라이브러리는이 의견에 보고 된 바와 같이 그러한 요청의 방출을 지원하지 않을 수도 있습니다 .


0

클라이언트 프로그램에서 Spring 프레임 워크의 RestTemplate을 사용하고 있으며 서버 측에서 Json 본문으로 GET 요청을 정의했습니다. 내 주요 목적은 당신과 동일합니다 : 요청에 많은 매개 변수가있을 때 본문에 넣는 것이 연장 된 URI 문자열에 넣는 것보다 더 깔끔한 것처럼 보입니다. 예?

그러나 슬프게도 작동하지 않습니다! 서버 측에서 다음 예외가 발생했습니다.

org.springframework.http.converter.HttpMessageNotReadableException : 필요한 요청 본문이 없습니다 ...

그러나 클라이언트 코드가 메시지 본문을 올바르게 제공한다고 확신하므로 무엇이 잘못 되었습니까?

RestTemplate.exchange () 메소드를 추적하여 다음을 발견했습니다.

// SimpleClientHttpRequestFactory.class
public class SimpleClientHttpRequestFactory implements ClientHttpRequestFactory, AsyncClientHttpRequestFactory {
    ...
    protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
        ...
        if (!"POST".equals(httpMethod) && !"PUT".equals(httpMethod) && !"PATCH".equals(httpMethod) && !"DELETE".equals(httpMethod)) {
            connection.setDoOutput(false);
        } else {
            connection.setDoOutput(true);
        }
        ...
    }
}

// SimpleBufferingClientHttpRequest.class
final class SimpleBufferingClientHttpRequest extends AbstractBufferingClientHttpRequest {
    ...
    protected ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput) throws IOException {
        ...
        if (this.connection.getDoOutput() && this.outputStreaming) {
            this.connection.setFixedLengthStreamingMode(bufferedOutput.length);
        }

        this.connection.connect();
        if (this.connection.getDoOutput()) {
            FileCopyUtils.copy(bufferedOutput, this.connection.getOutputStream());
        } else {
            this.connection.getResponseCode();
        }
        ...
    }
}

executeInternal () 메소드에서 입력 인수 'bufferedOutput'에는 내 코드에서 제공하는 메시지 본문이 포함되어 있습니다. 나는 디버거를 통해 그것을 보았다.

그러나 prepareConnection ()으로 인해 executeInternal ()의 getDoOutput ()은 항상 false를 리턴하여 bufferedOutput을 완전히 무시합니다. 출력 스트림에 복사되지 않습니다.

결과적으로 서버 프로그램이 메시지 본문을 수신하지 못하고 예외를 던졌습니다.

이것은 Spring 프레임 워크의 RestTemplate에 대한 예제입니다. 요점은 메시지 본문이 더 이상 HTTP 스펙에 의해 금지되지 않더라도 일부 클라이언트 또는 서버 라이브러리 또는 프레임 워크는 여전히 이전 스펙을 준수하고 GET 요청에서 메시지 본문을 거부 할 수 있다는 것입니다.


여기서 사양이나 의견을 올바르게 읽지 않았습니다. 요청 본문을 삭제하는 클라이언트 및 서버 사양 내에 있습니다. GET 요청 본문을 사용하지 마십시오.
Evert

@Evert 댓글을 제대로 읽지 못했습니까? :) Paul Morgan의 답변 (최고 타격 답변)으로 스크롤하여 주석을주의 깊게 읽으면 "HTTP / 1.1 사양"으로 참조되는 RFC2616은 더 이상 사용되지 않습니다. RFC 7230-7237. "요청을 처리 할 때 메시지 본문을 무시해야합니다"라는 인용문이 삭제되었습니다. 이제는 "메시지 본문에 대한 용도를 정의하지 않아도"요청 메시지 프레이밍이 메소드 시맨틱과 무관합니다 " ... "
Zhou

@Evert 또한 스프링 테스트 백엔드를 테스트하기 위해 REST 테스트 유틸리티 "rest-assured"를 사용하고있었습니다. 안심하고 스프링 부트 서버 측 모두 JET 본문을 GET 요청으로 유지했습니다! Sping-framework의 RestTemplate 만 GET 요청에서 본문을 삭제하므로 Spring-boot, rest-assured 및 RestTemplate은 잘못입니까?
Zhou

@Evert 마지막으로 임대하지는 않았지만 사람들이 GET 요청에 바디를 사용하도록 권장하지 않았지만 Sping-framework의 RestTemplate의 소스 코드를 분석하여 사용하지 말 것을 제안했습니다. 대답?
Zhou

나는 당신의 대답을 공감하지 않았습니다. GET 요청을 삭제하는 HTTP 구현 사양에 있음을 분명히하고 있습니다.
Evert
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.