38

私は自分が書いているいくつかのWebサービスを持っており、可能な限りRESTfulになろうとしています。IIS / ASP.NET/SharePoint内で実行されているHTTPHandlerを使用してこれらのWebサービスをホストしています。

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

IIS、ASP.NET、およびSharePointを使用すると、URLパス内の次の文字は、Urlエンコードされていても、HttpHandlerに到達しないことがわかりました(要求が爆発し、これを簡単に制御できません) :

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

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

  • (%23)

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

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

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

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

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

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

  3. HTTPPOSTとメッセージ本文を使用します。 特殊文字を使用する可能性のあるものはすべて、リクエストの本文に含める必要があります。 まともな解決策のように見えますが、投稿はべき等ではないと理解されており、(私が思ったように)一般的に変更を目的としています(ここでは変更は発生していません)。

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

  5. リクエストの大きさに応じて、上記の#3と#1または#2のいずれかを組み合わせて使用​​します。

  6. 他の???

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


URIの長さに関して、RFC2616Sec3.2.1は次のように述べています。

HTTPプロトコルでは、URIの長さに事前の制限はありません。サーバーは、提供するすべてのリソースのURIを処理できる必要があり、そのようなURIを生成できるGETベースのフォームを提供する場合は、無制限の長さのURIを処理できる必要があります。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.

さらに、InternetExplorerの最大URL長は2,083文字です。

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

4

11 に答える 11

34

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

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

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

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

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

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

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

于 2009-08-17T20:48:18.193 に答える
17

クエリが大きすぎてURIに入れられない場合は、クエリをリソースに変換します(保存された検索など)。ホテルの予約システム用のRESTfulAPIに取り組みました。検索クエリのパラメータ(設定、ルーミングリストなど)が多すぎるため、サーバーに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>
于 2010-12-20T19:21:25.403 に答える
6

HTTP 1.1仕様、特にセクション3.2UniformResourceIdentifiers9.1.1SafeMethodsを読むことをお勧めします。それらはうまくいけばあなたの質問に答えるでしょう。


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

于 2009-08-12T16:05:14.783 に答える
5

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

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

于 2009-08-16T02:01:24.820 に答える
2

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

分割されたパラメーターを使用して複数のGETをスローし、その方法でリクエスト全体を追跡することをお勧めしません...

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

于 2009-08-17T20:28:17.080 に答える
2

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

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

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

于 2009-08-12T15:54:43.697 に答える
2

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

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

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

于 2009-08-14T23:20:48.717 に答える
2

Roy Fieldingは、この状況でPOSTを使用することを承認する可能性がありますが、彼に尋ねる必要があります。

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

于 2009-08-18T09:21:52.950 に答える
1

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

于 2009-08-12T15:49:18.123 に答える
0

base64がそれを行う必要があります。それ以外の場合は、標準の%記号を使用します。

于 2009-08-17T12:23:09.333 に答える
0

サポートを検討してください:
-短いクエリ文字列を含む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」を混在させないように注意してください。

于 2016-03-21T14:50:05.740 に答える