web-dev-qa-db-ja.com

やや複雑なパラメータが必要な場合にHTTPリクエストを設計する最良の方法は何ですか?

作成中のWebサービスがいくつかあり、できるだけRESTfulになるようにしています。 IIS/ASP.NET/SharePoint内で実行されているHTTPHandlerを使用してこれらのWebサービスをホストしています。

私のサービスのほとんどはHTTP GETを期待しています。私はこれらの2つを持っているだけで、単にいくつかのデータ(つまり、クエリ)を返し、 Idempotent になりますが、パラメーターは多少複雑になる場合があります。どちらも、サービスのパラメーターに、少なくともURLのPATH部分では許可されない文字を含めることができます。

IIS、ASP.NET、およびSharePointを使用して、URLパス内の以下の文字は、URLエンコードされていてもHttpHandlerに到達しないことを発見しました(リクエストが爆発し、これを簡単に制御できません) :

  • %(%25)
  • &(%26)
  • *(%2a、ただしURLエンコードしませんでした)
  • +(%2b)
  • :(%3a)
  • <(%3c)
  • (%3e)

次の文字はHttpHandlerに到達しましたが、Urlがエンコードされていても、UriTemplateはそれらを適切に処理できませんでした。

  • (%23)

  • 。 (%2e、ただしUrlエンコードされませんでした。/の前の最後の文字である場合、UriTemplateは「。」を削除しました)
  • ? (%3f)
  • /(%2f-UrlEncodedであっても明らかな理由でUriTemplateが失敗する)
  • \(%5c)

だから、私は多少徹底していますが、クエリ文字列でこれらのURLエンコードされた文字をテストする必要があります。これは、ほとんどの部分で機能するようです。

私のサービスの1つでは、パラメーターである特殊文字は、意味的にはクエリ/フィルターの一部です(実際には検索サービスの検索用語です)。別のサービスでは、それらは実際にはクエリ/フィルターの一部ではないため、理想的にはクエリ文字列ではなくパス。

私の質問は、どのオプションが最適ですか?ここに私が知っているいくつかがあります:

  1. HTTP GETとクエリ文字列を使用します。特殊文字を使用する可能性のあるものはすべて、クエリ文字列とURLエンコードに含める必要があります。 これは私が傾いているところですが、非常に長いクエリ文字列が心配です(IEには2083の制限があります)

  2. パス内でHTTP GETおよびbase64エンコーディングを使用します。特殊文字を使用する可能性のあるパラメーターに RLの変更Base64 を使用し、必要に応じて、パスの一部としてそれらを追加します。 私はこれを試してみましたがうまくいきましたが、ちょっと醜いです。非常に長いクエリ文字列に関する懸念はまだあります。

  3. HTTPを使用POST and message body。特殊文字を使用する可能性のあるものはすべて、リクエストの本文に含める必要があります。適切な解決策のように見えますが、投稿はでないと理解されていますべき等 および(私は考えました) (ここでは変更は発生していませんが)通常は変更を意味します。

  4. HTTP GETとメッセージ本文を使用します。特殊文字を使用する可能性のあるものはすべて、リクエストの本文に含める必要があります。 SO:HTTP GET with request bodyRoy Fielding によると、これは悪い考えのようです。

  5. リクエストのサイズに応じて、上記の#3と#1または#2の組み合わせを使用します。

  6. その他???

場合によっては、特殊文字を防ぐために状況を変えることができる場合があります(そうすることもあります)が、すべての場合にこれを行うことはできません。


URIの長さについては、 RFC2616 Sec3.2.1 は次のように述べています。

HTTPプロトコルでは、URIの長さに事前の制限はありません。サーバーは、サービスを提供するすべてのリソースのURIを処理できなければならず(MUST)、そのようなURIを生成できるGETベースのフォームを提供する場合は、無制限の長さのURIを処理できる必要があります(SHOULD)。 URIがサーバーが処理できる長さより長い場合、サーバーは414(Request-URI Too Long)ステータスを返す必要があります(セクション10.4.15を参照)。

  Note: Servers ought to be cautious about depending on URI lengths
  above 255 bytes, because some older client or proxy
  implementations might not properly support these lengths.

さらに Internet Explorerでの最大URL長は2,083文字です

関連: RESTで複雑なクエリを渡す方法?

35
Kirk Liemohn

HTTP 1.1仕様 、特に .2 Uniform Resource Identifiers および 9.1.1 Safe Methods のセクションを読むことをお勧めします。それらはうまくいけばあなたの質問に答えます。


追加情報は次のとおりです。

6
Gumbo

これを行う完璧な方法はありません。

正しいHTTP/RESTの方法は、GETを使用し、URL内のすべてのパラメーターをクエリ引数として使用することです。このアプローチには2つの実際的な問題があります。

  1. URLエンコードされていても、サーバーソフトウェアが一部の文字を正しく渡していない。実際、これは私を驚かせます。URLを介して%を取得することさえできないので、何が起こっているのかをもっとよく見る必要があります。あなたのフレームワークはPATH_INFOまたはその他の未処理の文字へのrawアクセスを提供しますか?それはあなたに回避策を与えるかもしれません。
  2. クエリ文字列が長すぎる可能性があります。 MSIEでの2083バイトの制限について言及しています。これは、MSIEがAPIのクライアントであるかどうかによって、実際的な問題である場合とそうでない場合があります。 (つまり、JavaScriptを介してJSON APIを呼び出します)。しかし、私の経験では、非常に長いURLはいくつかの場所で不思議に壊れてしまいます。パスに沿ったプロキシキャッシュ、さらにはステートフルファイアウォール。クライアントとネットワークパスを完全に制御している場合は、長いURLの危険に耐えることができます。パブリックAPIの場合は、忘れてください。

うまくいけば、環境内で簡単なGETを機能させることができます。クエリデータを小さくするために、APIのリファクタリングを検討することもできます。

しかし、GETを機能させることができない場合はどうでしょうか?あなたはいくつかの選択肢を提案します。そのうちの2つはすぐに解雇します。 GETリクエストの本文にコンテンツを含めないでください。試してみるとソフトウェアが多すぎて壊れてしまい、とにかくそれはキャプチャしようとしているREST精神に違反しています。そして、私はbase64エンコーディングを使用しません。問題を回避するのに役立つかもしれません。 1、サーバーはURLの一部の文字を正しく処理しません。ただし、正しく適用しないと、実際にはURLが長くなり、短くなりません。問題が複雑になります。2. base64を正しく行って圧縮を含めても、URLは大幅に短くなりませんクライアントをはるかに複雑にします。

最も実用的なソリューションは、おそらくオプション3、HTTP POSTです。これはRESTfulではありません。読み取り専用クエリにはGETを使用する必要があります。また、RESTアプローチによるGETのキャッシュなどの利点は失われます。その一方で、さまざまなインターネットインフラストラクチャとソフトウェアライブラリを使用すると、正しく機能します。 。次に、POST本文でmultipart/form-dataエンコーディング、JSON、またはXMLのいずれかを使用して、必要なだけデータを渡すことができます(SOAPを使用して2つの主要なパブリックWebサービスを構築しました。これは単なるPOST上のXMLです。醜くてRESTfulではありませんが、確実に機能します。)

RESTは優れた設計パラダイムです。ガイドラインです。それがあなたのアプリに合わないなら、あなたがそれに固執する必要があると感じないでください。 HTTPは、GETを使用して大量のデータをサーバーに渡すのは得意ではありません。巨大なクエリパラメータが必要な場合は、他のことを行ってください。

29
Nelson

クエリが大きすぎてURIに入らない場合は、クエリをリソース(保存された検索など)に変換します。私はホテルの予約システム用の安らかなAPIに取り組みました。検索クエリに含まれるパラメーター(設定、ルーミングリストなど)が多すぎるため、これをリソースに変換して、サーバーにPOST)します。サーバーは、一意に識別するURIで応答します投稿されたクエリとその結果である本文を検索します。

POST http://hotels.xyz/searches
body <search><query>...</query></search>

応答

201 Created - Location: http://hotels.xyz/searches/someID
Body <search><query>...</query><results>...</results></search>
14
redben

他に何も解決しない場合は、HTTP GETでカスタムHTTPヘッダーを使用します。 HTTPヘッダーは、ほぼすべてのクライアントで設定できます。

通常、クエリ文字列ではURLパラメータを使用するのが最適です。 URLパラメータが多すぎる場合は、より細かいサービスに分割する必要があることを示しています。

5
lenkite

ロイフィールディング は、この状況でPOSTを使用することを承認する可能性がありますが、彼に尋ねる必要があります。

一般に、ユーザー提供のデータがサーバーに提供されることを伴うほとんどのアプリケーションは安全ではありません。 唯一の例外は、情報が一般化されたクエリパラメータの形式である場合で、GETとPOSTの間にはトレードオフがあります。通常、これにはパラメーターのコンテンツのサイズが含まれますGETは、パラメーターを意味のあるURIとして表現できる場合にのみ望ましいです。

2
Steven Huwig

HTTP GETリクエストを使用して、クエリ文字列にパラメータを配置する必要があります。一部の古いWebブラウザーの制限は問題ではありません。WebブラウザーでAPIを参照しているのは開発者(または少なくとも技術的な人)だけだからです。

クライアントアプリケーションはnotでAPIが提供するURLを操作する必要があることに注意してください。 URLはクライアントに対する不透明な識別子であり、特定のリソースが見つかる可能性のある場所にURLを誘導するためにのみ使用されます。

何らかの理由でこれが不可能な場合は、POSTリクエストを本文にフォームエンコードされたパラメータとともに使用します。完全にRESTfulになるわけではありませんが、リソースが適切に設計されていると仮定すると、クライアントコードへの影響は最小限でなければなりません。

2
John Millikin

サーバーでこれらの長いURLを生成している場合は、パス情報の圧縮を利用できます。

したがって、/?param1 = bla-bla&param2 = bla-blaのようなものがあれば、そのパラメータを圧縮して、URLを/?query = ASsadcnfAFFASFscnsdlcのようにします。

そのようなリクエストを受け取ったら、それらを解凍してパラメータ文字列を解析するだけです

2
glaz666

私は間違いなくあなたが始めたところから始めました:URL短縮。パラメータ名(?a = XXX; b = YYY; c = zzz);を短くしようと思います。クエリ全体をBase64に再エンコードします。 Base64のGZip。ハフマンはGZipをエンコードします。 ... 命をかけて。短縮がすべ​​てのケースで機能しないというインクリングを取得したら(無期限に追加できる動的フィルター作成システムがあるか、w/eがある場合)、すべてを実行しようとしていることを認めなければなりません。単一のリクエスト内では機能しない可能性があります...

分割パラメーターを使用して複数のGETをスローし、リクエスト全体でそのように追跡することをお勧めするつもりはありません...

私が提案できる唯一の「堅牢な」方法は、要求されたクエリ文字列を1つの要求(POST)に格納/設定し、データストア(filterID)内の要求パラメーターの場所を識別する固定サイズのID(またはGUID)を返すことです。次に、完全なフィルタークエリ文字列値の代わりに、filterIDトークンを使用して実際のGETリクエストを作成します。これにより、filterIDに基づいて応答をキャッシュするなど、あらゆる種類の優れた機能が可能になるため、(理論的には)同じフィルターを後で再利用できます(手動で再入力する代わりに、「ラベル」をフィルター本体と一緒に保存してから選択できます)最後の5つのフィルターはラベルでフィルター処理されます)、または少なくともページを更新するたびにフィルター要求全体が再送信されないように、それらをデータと共に保存します。

2
ifatree

HTTP POSTを目指しています。 PHP(またはあなたが使用しているもの))に到達するとうまくトークン化され、他の人が持っているようなサイズ制限はありません。

1
Mark L

サポートを検討してください:
-短いクエリ文字列を使用したGETリクエスト
-POSTリクエストの本文に長いクエリ文字列があり、X-HTTP-Method-Override:GET( https://en.wikipedia.org/wiki/List_of_HTTP_header_fields

新しい注文の一括作成である「POST/orders」と、注文の検索である「X-HTTP-Method-Override:GET」と「POST/orders」を混在させないように注意してください。

0

base64はそれを行うべきです。それ以外の場合は、標準の%記号を使用します。

0
user142019