リクエストボディを含むHTTP GET


2110

アプリケーション用の新しいRESTful Webサービスを開発しています。

特定のエンティティに対してGETを実行すると、クライアントはエンティティのコンテンツを要求できます。一部のパラメーターを追加する場合(リストの並べ替えなど)、これらのパラメーターをクエリ文字列に追加できます。

あるいは、リクエストの本文でこれらのパラメーターを指定できるようにしたいです。 HTTP / 1.1はこれを明示的に禁止していないようです。これにより、より多くの情報を指定できるようになり、複雑なXML要求を指定しやすくなる場合があります。

私の質問:

  • これは完全に良いアイデアですか?
  • HTTPクライアントは、GETリクエスト内のリクエスト本文の使用に問題がありますか?

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


552
利点は、XMLまたはJSON要求の本文を簡単に送信できること、長さに制限がないこと、およびエンコードが容易であること(UTF-8)です。
エバート

29
あなたが求めているものがリクエストボディを許可する安全でべき等な方法であるなら、あなたはSEARCH、PROPFIND、REPORTを見ることを望むかもしれません。もちろん、GETを使用せず、リクエストボディを含めると、キャッシュが多少損なわれます。
Julian Reschke

226
@fijiaaron:それは3年後のことです。それ以来、私はWebサービスの作成に豊富な経験を積んでいます。基本的に私がここ数年やってきたことはこれだけです。安全に言うことができますが、GETリクエストにボディを追加することは非常に悪い考えです。上位2つの回答は岩のように立っています。
2012

26
@Ellesedil:簡単に言えば:POSTよりもGETを使用することで得られる利点は何でも、HTTPの設計方法により存在します。このように標準に違反すると、これらの利点はなくなります。したがって、POSTの代わりにGET +リクエストボディを使用する理由は1つだけ残っています:美学。美学よりも堅牢なデザインを犠牲にしないでください。
2014年

7
エバートが言ったことを強調するために:「長さの制限はありません」。クエリパラメーターを使用したGETが長さの制限(2048)を超えている場合、クエリ文字列情報をjsonオブジェクト(リクエストの本文など)に配置する以外に他にどのような選択肢がありますか。
キーランライアン

回答:


1725

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
キャッシング/プロキシは、あなたが破る可能性が最も高い2つのものです、はい。「セマンティクス」は、「他のコンポーネントを作成する人々が他のコンポーネントが動作することを期待する方法」の別の言い方です。セマンティクスに違反すると、そのセマンティクスを尊重することを期待しているものを人々が書いた場所で物事が壊れる可能性が高くなります。
スチュアートP.ベントレー

108
Elasticsearchは、GETでHTTPリクエストボディを利用するかなり主要な製品です。彼らのマニュアルによると、HTTPリクエストが本文を持つことをサポートするかどうかは定義されていません。私は個人的にGETリクエストの本文の入力に慣れていませんが、意見が異なっているようで、何をしているのかを知っている必要があります。 elastic.co/guide/en/elasticsearch/guide/current/...
GordonM

25
@iweinがGETリクエスト本文に意味を与えることは、実際には仕様に違反していませんHTTP / 1.1は、サーバーが本文を無視する必要があることを指定していますが、RFC 2119は、実装者が正当な理由がある場合に「SHOULD」句を無視できることを指定しています。むしろ、GETボディを変更してもレスポンス変更されないと想定した場合、クライアント仕様に違反します。
Emil Lundberg、2015

107
「HTTP / 1.1仕様」として参照されるRFC2616は廃止されました。2014年には、RFC 7230〜7237に置き換えられました。引用「リクエストを処理する場合、メッセージ本文は無視すべきです」は削除されました。これは単に「メソッドがメッセージ本文の使用を定義していなくても、リクエストメッセージのフレーミングはメソッドのセマンティクスに依存しない」です。「2番目の引用」「GETメソッドは、あらゆる情報を取得することを意味します... Request-URIによって識別されます」た削除されました。だから、私は答えを編集することをお勧めします@Jarl
Artem Nakonechny

28
私はそれが古い糸であることを知っています-私はそれにつまずきました。@Artem Nakonechnyは技術的には正しいですが、新しい仕様では、「GETリクエストメッセージ内のペイロードにはセマンティクスが定義されていません。GET リクエストでペイロードボディを送信すると、既存の実装がリクエストを拒否する可能性があります。」 したがって、回避できるかどうかはまだあまり良い考えではありません。
fastcatch 2017

289

HTTP仕様で明示的に除外されていない限り、それを行うことができますが、人々がそのように機能することを期待していないという理由だけで、それを回避することをお勧めします。HTTPリクエストチェーンには多くのフェーズがあり、それらは「ほぼ」HTTP仕様に準拠していますが、Webブラウザーで従来使用されているように動作することが保証されます。(透過プロキシ、アクセラレータ、A / Vツールキットなどを考えています)

これは、ロバスト性の原則の背後にある精神であり、大まかに「受け入れるものは寛大であり、送信するものは保守的である」ため、正当な理由なしに仕様の境界を押し広げたくない。

しかし、もしあなたが正当な理由があるなら、それのために行ってください。


228
堅牢性の原則には欠陥があります。あなたが受け入れることに寛大であるならば、あなたががらくたを受け入れるからといって、養子縁組に関して何らかの成功があれば、あなたはがらくたになります。そのため、インターフェースを進化させることが難しくなります。HTMLを見てください。それが実行中の反発原理です。
Eugene Beresovsky、2011

27
プロトコルの採用(および乱用)の成功と幅広さは、堅牢性の原則の価値を物語っていると思います。
caskey 2011

39
本物のHTMLを解析してみたことはありますか?自分で実装するのは現実的ではありません。そのため、Google(Chrome)やApple(Safari)などの非常に大きなプレーヤーを含むほとんどすべての人がこれを実行せず、既存の実装に依存していました(結局、すべてKDEのKHTMLに依存していました)。その再利用はもちろん素晴らしいですが、.netアプリケーションでhtmlを表示してみましたか?-管理されていない-IE(または同様の)コンポーネントを、その問題とクラッシュとともに埋め込む必要があるか、テキストを選択することさえできない、利用可能な(codeplex上の)管理されたコンポーネントを使用する必要があるため、これは悪夢です。
Eugene Beresovsky、2011

6
HTTP仕様では、GETリクエストでボディデータを許可するだけでなく、これも一般的な方法です。人気のあるElasticSearchエンジンの_search APIは、クエリをJSONボディに添付したGETリクエストを推奨しています。不完全なHTTPクライアント実装への譲歩として、POSTリクエストもここで許可します。
Christian Pietsch 2013年

3
@ChristianPietsch、それは今日の一般的な慣行です。4年前はそうではありませんでした。仕様では、クライアントがオプションでエンティティをリクエストに含めることを明示的に許可(MAY)しますが(セクション7)、MAYの意味はRFC2119で定義されており、GETリクエストでエンティティを削除しながら、(くだらない)プロキシサーバーを仕様に準拠させることができます。具体的には、クラッシュしない限り、含まれているエンティティではなく、リクエストヘッダーを転送することで「機能の低下」を提供できます。同様に、異なるプロトコルレベル間でプロキシを行う場合、どのバージョンの変更を行う必要があるか(MAY / SHOULD)について多くのルールがあります。
caskey 2013年

151

キャッシュを利用しようとすると、問題が発生する可能性があります。プロキシーは、GET本体を調べて、パラメーターが応答に影響を与えるかどうかを確認しません。


10
ETag / Last-Modifiedヘッダーフィールドを使用すると、このように役立ちます。「条件付きGET」を使用すると、プロキシ/キャッシュがこの情報に作用できます。
jldupont 2010年

2
@jldupontキャッシュは、古くなった応答を再検証できるかどうかを確認するためにバリデーターの存在を使用しますが、それらはプライマリまたはセカンダリキャッシュキーの一部としては使用されません。
Darrel Miller

クエリパラメータの本文のチェックサムでこれを修正できます
Adrian May

73

restclientRESTコンソールもこれをサポートしていませんが、curlはサポートしています。

HTTPの仕様では、 4.3節で述べています

リクエストメソッドの仕様(セクション5.1.1)がリクエストでのエンティティボディの送信を許可しない場合、メッセージボディをリクエストに含めることはできません。

セクション5.1.1は、さまざまな方法についてセクション9.xにリダイレクトします。メッセージ本文を含めることを明示的に禁止するものはありません。しかしながら...

セクション5.2は言う

インターネット要求によって識別される正確なリソースは、Request-URIとHostヘッダーフィールドの両方を調べることによって決定されます。

そしてセクション9.3は言う

GETメソッドは、Request-URIで識別される情報(エンティティーの形式)を取得します。

これは、GET要求を処理するときに、サーバーがRequest-URIおよびHostヘッダーフィールド以外のものを調べる必要がないことを示唆しています。

要約すると、HTTP仕様はGETでメッセージ本文を送信することを妨げるものではありませんが、すべてのサーバーでサポートされていなかったとしても不思議ではありません。


2
Pawには、本文でのGETリクエストをサポートするオプションもありますが、設定で有効にする必要があります。
s.Daniel、2015年

「GETメソッドとは、Request-URIで識別される情報(エンティティーの形式)を取得することを意味します。」次に、すべてのエンティティを取得するGETエンドポイントを持つことは技術的には違法ですか?たとえばGET /contacts/100/addresses、の人の住所のコレクションを返しますid=100
Josh M.

REST APIをテストするための残りのJavaライブラリは、本文付きのGETリクエストをサポートしていません。Apache HttpClientもそれをサポートしていません。
Paulo Merson 2016

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:PARAM curl -XGET 'http://localhost:9200/_count?pretty&source=%7B%22query%22%3A%7B%22match_all%22%3A%7B%7D%7D%7D'
アルン

40
複雑なクエリは、httpヘッダーの最大長に達する可能性があります。
s.Daniel

11
ボディを含めるのは悪い習慣だと考えられていたので、この質問に私を連れて行ったのはelasticsearchドキュメントを読んでいた
PatrickWalker

1
複雑なクエリである必要はありません。単純なスクロールでも、非常に長いscroll_id(多くのシャードを持つクラスター内)を返す可能性があり、そこに追加された場合、URLの最大長がオーバーランする可能性があります。
ブレントHronik 16

11
Elasticsearchは、POSTを使用して同じリクエストをサポートします。データのクエリに関しては、GETはPOSTよりも意味的に正しいと感じたため、GETで本文を許可することのみを選択しました。Elasticsearchがこのスレッドで非常に言及されているのはおかしいです。慣習に従う理由として、1つの例(人気のある製品ではあります)は使用しません。
DSO 2017

33

あなたが達成しようとしていることは、ずっと一般的な方法で長い間行われており、GETでペイロードを使用することに依存しない方法です。

特定の検索メディアタイプを作成するか、よりRESTfulにしたい場合は、OpenSearchなどを使用して、サーバーが指示したURI(/ searchなど)に要求をPOSTできます。次に、サーバーは検索結果を生成するか、最終的な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、2011年

14
これは賢い方法ですが、複雑すぎて非効率的です。次に、検索条件を含むPOSTを送信し、POSTからの応答としてURIを取得し、検索条件URIを含むGETをサーバーに送信して、条件をGETし、結果を返送する必要があります。(URIにURIを含めることは技術的に不可能ですが、255文字を超えないものの中で255文字までのものを送信することはできないため、部分的な識別子とサーバーを使用する必要がありますPOSTされた検索条件のURIを解決する方法を知る必要があります。)
fijiaaron 2012

30

本文でGETを送信するか、POSTを送信してRESTの信仰を放棄することができます(それほど悪くはありません。5年前は、その信仰のメンバーは1人しかいませんでした-彼のコメントは上記にリンクされています)。

どちらもすばらしい決定ではありませんが、GET本文を送信すると、一部のクライアント(一部のサーバー)の問題を防ぐことができます。

POSTを実行すると、一部のRESTishフレームワークに障害が生じる可能性があります。

Julian Reschkeさんは、「SEARCH」のような非標準のHTTPヘッダーを使用することを上記で提案しましたが、サポートされる可能性がさらに低いことを除けば、エレガントなソリューションになる可能性があります。

上記のそれぞれを実行できるクライアントと実行できないクライアントをリストすることは、最も生産的です。

(私が知っている)本文付きのGETを送信できないクライアント:

  • XmlHTTPRequest Fiddler

本文付きのGETを送信できるクライアント:

  • ほとんどのブラウザ

GETから本体を取得できるサーバーとライブラリ:

  • Apache
  • PHP

GETから本文を削除するサーバー(およびプロキシ):


2
Squid 3.1.6はまた、Content-Lengthが0または設定されていない場合にGETボディを
削除し

2
フィドラーはそうしますが、警告します。
toddmo 2015

SEARCHメソッドが途中で壊れる可能性があると言っていますか?プロキシがメソッドを理解しない場合、それらはそのまま通過することが期待されているため、なぜそれが何かを壊すと思うのかよくわかりません...
Alexis Wilke

22

この質問はIETF HTTP WGに寄せました。Roy Fielding(1998年のhttp / 1.1ドキュメントの著者)からのコメントは、

「...実装は、受信された場合、その本体を解析して破棄する以外のことを行うために壊れます。」

RFC 7213(HTTPbis)は次のように述べています:

「GETリクエストメッセージ内のペイロードにはセマンティクスが定義されていません。」

GETリクエストボディでのセマンティックな意味は禁止されていること、つまりリクエストボディを結果に影響を与えるために使用できないことが意図されていたことは明らかです。

GETに本文を含めると、さまざまな方法でリクエストを確実に中断するプロキシが世の中に存在します。

要約すると、それを行わないでください。


21

どのサーバーがそれを無視しますか?– fijiaaron 2012年8月30日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.

また、BingやAppleなどからAkamaiGhostが提供する400 Bad Requestも受け取ります。

そのため、ボディエンティティでGETリクエストを使用することはお勧めしません。


65
この例は無意味です。通常、人々がGETリクエストに本文を追加しようとするとき、それは自分のカスタムサーバーがそれを処理できるためです。したがって問題は、他の「可動部分」(ブラウザ、キャッシュなど)が正しく機能するかどうかです。
Pacerier

6
ペイロードはGET その特定のエンドポイントのに対して期待されていない(または賢明な)ものではないため、これは悪い要求GETです。一般的なケースではの使用とは関係ありません。コンテンツが特定のリクエストのコンテキストで意味のある形式でなかった場合、ランダムなペイロードがPOST同じように簡単に壊れ、同じを返す可能性が400 Bad Requestあります。
nobar 2018

そして、そのエンドポイント全体だけでなく、特定のURLでも
ローレンスドル

1
これは、そのURLでのGoogleのサーバー実装にすぎないため、無関係です。したがって、この質問には意味がありません
ジョエルダックワース

get request + bodyでfirebase関数を使用しようとしていたので、私にとっては役に立ちました。このエラーは非常にわかりにくく、理解するのが難しい場合があります。
scrimau

19

RFC 2616、セクション4.3、 "メッセージ本文":

サーバーはどんなリクエストでもメッセージボディを読んで転送すべきです。リクエストメソッドにエンティティボディの定義されたセマンティクスが含まれていない場合、リクエストを処理するときにメッセージボディを無視する必要があります(SHOULD)。

つまり、サーバーは常にネットワークから提供されたリクエスト本文を読み取る必要があります(Content-Lengthを確認するか、チャンクボディを読み取るなど)。また、プロキシは受け取ったそのようなリクエスト本文を転送する必要があります。次に、RFCが指定されたメソッドの本文のセマンティクスを定義している場合、サーバーは実際に要求本文を使用して応答を生成できます。ただし、RFC がそうしない場合本文のセマンティクスを定義しサーバーはそれを無視する必要があります。

これは、上記のフィールディングからの引用と一致しています。

9.3項「GET」では、GETメソッドのセマンティクスについて説明し、リクエストの本文については触れていません。したがって、サーバーはGET要求で受信した要求本文を無視する必要があります。


セクション9.5の「POST」でもリクエストの本文に言及していないため、このロジックには欠陥があります。
CarLuva 2014年

9
@CarLuva POSTセクションは、「POSTメソッドは、オリジンサーバーが囲まれたエンティティを受け入れることを要求するために使用されます...」と言います。エンティティボディセクションは、「エンティティボディはメッセージボディから取得されます...」 POSTセクションでは、メッセージ本文について言及していますが、POSTリクエストのメッセージ本文に含まれるエンティティ本文を間接的に参照しています。
frederickf 2014

9

XMLHttpRequestによると、これは無効です。標準から:

4.5.6 send()メソッド

client . send([body = null])

リクエストを開始します。オプションの引数は、リクエストの本文を提供します。リクエストメソッドがGETまたはの場合、引数は無視されHEADます。

をスローします InvalidStateErrorいずれかの状態が開かれていないか、send()フラグが設定されている場合は例外をます 。

この方法は、以下の手順を実行する必要があります。send(body)

  1. 状態がそうでない場合 開かれてInvalidStateError例外をます。
  2. send()フラグが設定されている場合は、InvalidStateError例外をます。
  3. リクエストメソッドがGETまたはHEAD本文を設定しますをnullします。
  4. ならがnullのは、次の手順に進みます。

ただし、GETリクエストには大きな本文コンテンツが必要になる可能性があるため、そうすべきではないと思います。

したがって、ブラウザーのXMLHttpRequestに依存している場合は、機能しない可能性があります。


1
XMLHttpRequestが実装であるという事実のために反対票を投じました。実装することになっている実際の仕様を反映していない場合があります。
フロム

10
上記の反対投票は間違っています。一部の実装がGETでの本文の送信をサポートしていない場合は、仕様に関係なく、それが理由ではない可能性があります。私が実際に取り組んでいるクロスプラットフォーム製品でこの正確な問題に遭遇しました-XMLHttpRequestを使用するプラットフォームのみがgetの送信に失敗しました。
pjcard 2018年

8

キャッシュ可能なJSON / XMLボディをWebアプリケーションに送信したい場合、データを配置するための唯一の妥当な場所は、RFC4648:Base 64 Encoding with URL and Filename Safe Alphabetでエンコードされたクエリ文字列です。もちろん、JSONをurlencodeしてURLパラメータの値に配置することもできますが、Base64の方が結果は小さくなります。URLサイズの制限があることに注意してください。さまざまなブラウザーでのURLの最大長は何ですか?を参照してください

Base64のパディング=文字はURLのparam値としては悪いと思われるかもしれませんが、そうではないようです-次のディスカッションを参照してくださいhttp : //mail.python.org/pipermail/python-bugs-list/2007-February/037195.html。ただし、パディング付きのエンコードされた文字列は空の値を持つparamキーとして解釈されるため、param名なしでエンコードされたデータを配置しないでください。のようなものを使用します?_b64=<encodeddata>


これはかなり悪い考えだと思います:)しかし、もし私がこのようなことをするなら、代わりにカスタムHTTPヘッダーを使用します(そして、常にVary:を返送するようにしてください)。
2013

悪いかではないが、なんとか:)ヘッダ内のデータとがデータサイズと同様の問題があり、参照stackoverflow.com/questions/686217/...を。しかしVary、ヘッダーに言及してくれてありがとう、私はそれが本当の可能性であることを知りませんでした。
gertas 2013

6

私はこれを助言しません、それは標準的な慣行に反し、その見返りにはそれほど多くを提供しません。オプションではなく、コンテンツの本文を保持したい。


5

非準拠のbase64エンコードされたヘッダーはどうですか?「SOMETHINGAPP-PARAMS:sdfSD45fdg45 / aS」

長さ制限hm。POST処理で意味を区別できませんか?並べ替えのような単純なパラメーターが必要な場合、なぜこれが問題になるのかわかりません。あなたが心配していることは確かだと思います。


x-プレフィックスを使用して必要なパラメーターを送信できます。ヘッダーの長さの制限は、完全にサーバーの任意の制限になります。
Chris Marisic

4

プロトコルがOOPをサポートしていないため、RESTに不満を感じています。 Get方法が証明されている。ソリューションとして、DTOをJSONにシリアル化し、クエリ文字列を作成できます。サーバー側では、クエリ文字列をDTOに逆シリアル化できます。

見てみましょう:

メッセージベースのアプローチは、Getメソッドの制限を解決するのに役立ちます。リクエスト本文と同様に、任意のDTOを送信できます

Nelibur Webサービスフレームワークは、使用できる機能を提供します

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を使用してください。
2014

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 Muzatk​​o

3

私見では、JSONエンコードされた(つまりencodeURIComponent)をで送信するだけでURLよいので、HTTP仕様に違反せずにJSONサーバーにアクセスできます。


28
そうですが、主な問題は長さ制限です。どうすれば対処できますか?
セバス2017年

2

GETでリクエストボディを使用するよりもはるかに優れたオプションのリストがあります。

カテゴリと各カテゴリのアイテムがあるとします。どちらもIDで識別されます(この例では、 "catid" / "itemid")。特定の「順序」で別のパラメーター「sortby」に従ってソートしたい。「sortby」と「order」のパラメーターを渡したい場合:

あなたはできる:

  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の一部を使用して忘れる1

ビューアのGETリクエストに本文が含まれている場合、CloudFrontはHTTPステータスコード403(禁止)をビューアに返します。

このコメントで報告されているように、クライアントライブラリもそのようなリクエストの発行をサポートしていない場合があります。


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コメントを正しく読みませんでしたか?:) Paul Morganの回答(一番ヒットした回答)までスクロールしてコメントを注意深く読むと、次のことがわかります:「「HTTP / 1.1仕様」として参照されているRFC2616は廃止されました。2014年には、 RFC 7230-7237。「リクエストを処理する場合、メッセージ本文は無視する必要があります」という引用が削除されました。「リクエストメッセージのフレーミングは、メソッドがメッセージ本文の使用を定義していない場合でも、メソッドのセマンティクスとは無関係です」 ...」
Zhou

@Evertさらに、RESTテストユーティリティ「rest-assured」を使用して、Springブートバックエンドをテストしていました。安心とSpring-bootのサーバー側の両方で、GETリクエストのためにJson本体を保持しました!SpingフレームワークのRestTemplateのみがGETリクエストから本文を削除するので、Spring-boot、rest-assured、およびRestTemplateは間違っていますか?

@Evert最後ですがリースではありません、GETリクエストでbodyを使用するように人々に促しませんでした。逆に、SpingフレームワークのRestTemplateのソースコードを分析してそうしないことを提案しました。回答?

私はあなたの答えに反対票を投じませんでした。私は、GETリクエストをドロップする任意のHTTP実装があることを明確だある仕様に。
エバート
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.