重複するHTTP GETクエリキーの信頼できる位置


137

次のようなHTTP GETクエリ文字列の重複フィールドの動作に関する信頼できる情報を見つけるのに問題があります。

http://example.com/page?field=foo&field=bar 

特に注文が維持されるかどうか。ほとんどのWeb指向言語は、キー「フィールド」に関連付けられたfooとbarの両方を含む配列を生成しますが、この点について(RFCなどで)権威あるステートメントが存在するかどうか知りたいです。RFC 3986には、3.4. Querykey = valueペアを参照するセクションがありますが、順序の解釈方法やフィールドの重複方法などについては何も述べられていません。これは、バックエンドに依存し、そのRFCの範囲ではないため、理にかなっています...

事実上の標準が存在しますが、好奇心から、それについての信頼できる情報源を見たいと思います。


それについても不思議に思っています。もう1つは、クエリ文字列のパラメーターをPOST本文のパラメーターとマージすることに関する仕様です。
ティロ

コードランチでは、注文の保証はないと言われています。しかし、そのスレッドは古く、誰もそれをバックアップしていません:coderanch.com/t/357197/Servlets/java/getParameterValues-order
Thilo

1
サーバーがクエリ文字列の順序を保持することに加えて、ブラウザがDOM(または他の固定された)順序でそれらを送信することについての質問もあります。
ティロ

回答:


112

これに関する仕様はありません。あなたは好きなことをするかもしれません。

典型的なアプローチには、first-given、last-given、array-of-all、string-join-with-comma-of-allなどがあります。

未加工のリクエストが次のとおりだとします。

GET /blog/posts?tag=ruby&tag=rails HTTP/1.1
Host: example.com

次にrequest.query['tag']、言語またはフレームワークに応じて、何を生成するかについてさまざまなオプションがあります。

request.query['tag'] => 'ruby'
request.query['tag'] => 'rails'
request.query['tag'] => ['ruby', 'rails']
request.query['tag'] => 'ruby,rails'

12
質問のポイントに加えて、['rails'、 'ruby'](異なる順序)のオプションもあります。
ティロ

2
確かに多くのことができます。
yfeldblum 2009年

7
.NETは配列としてあなたに与えます(私はそれをテストしたとき私は順序を気にしていませんでした)、PHPは常にあなたに最後のJavaを与え、少なくともJava(少なくともJavaに基づいて使用したシステム)は常に最初の値を与えます。stackoverflow.com/questions/1809494/...
SimonSimCity

17
これは、HTTPパラメータ汚染と呼ばれる攻撃に基づいており、OWASPによって解析されていますowasp.org/images/b/ba/AppsecEU09_CarettoniDiPaola_v0.8.pdf 9ページでは、あなたは、20のシステムのリストと、それらがどのように処理するかを記述を見つけることができますこの問題。
SimonSimCity 2012

1
@SimonSimCityに加えて、オプションのインデックス付きの角括弧をパラメーター名に追加すると、PHPは実際に配列を作成します。
マーティンエンダー2013

14

PHPの場合(少なくともバージョン4.4.4以降)、次のように機能することを確認できます。

GET /blog/posts?tag=ruby&tag=rails HTTP/1.1
Host: example.com

結果は:

request.query['tag'] => 'rails'

だが

GET /blog/posts?tag[]=ruby&tag[]=rails HTTP/1.1
Host: example.com

結果は:

request.query['tag'] => ['ruby', 'rails']

この動作は、GETデータとPOSTデータの場合と同じです。


1
[]接尾辞は本当に奇妙な行動のように思えるが、あなたはjQueryの経由の引数として配列を送信しようとした場合.ajax()、それは自動的に同じ方法であなたのためにそれらを追加します。これはPHPユーザーの利益になるようです。
Ian Clark

4
@IanClarkこれは、PHPコーダーにとって直感的です-プレーンなPHPでは$foo[] = 1、配列に追加します。Django(Python)も同じことを行います。
Izkata

Apache Tomcatでコンマ連結された文字列を返すことを確認できます。
Gaurav Ojha

8

yfeldblumの答えは完璧です。

最近気付いた5つ目の動作についてのメモ:Windows Phoneでは、クエリキーが重複しているURIでアプリケーションを開くと、NavigationFailed with:

System.ArgumentException:同じキーの項目が既に追加されていました。

犯人はSystem.Windows.Navigation.UriParsingHelper.InternalUriParseQueryStringToDictionary(Uri uri, Boolean decodeResults)

したがって、システムはあなたがそれをあなたが望む方法で処理することさえ許さず、それを禁止します。独自のフォーマット(CSV、JSON、XMLなど)とuri-escape-itを選択するための唯一のソリューションが残ります。


2
これは、設計上の選択というよりは、その機能の内部バグのようです。おそらく関数は、作成中のディクショナリ内の重複キーをチェックしません。もちろん、辞書には一意のキーが必要です。
gligoran 2016年

1
したがって、サーバーではなくクライアントのブラウザがこの状況でエラーをスローしていますか?バグのようです。このバグが今日でも存在するのでしょうか?
ジョンシュナイダー、

1
@JonSchneiderはい、クライアントはNavigationFailedそのようなURIをスローしています。しかし、私を許して、私はこの投稿の1か月後にWindows(Phone)の開発を中止し、macOS(iOS)に移動したので、この問題を追跡することはできなくなりました。
クール2018

5

ほとんど(すべて?)のフレームワークは保証を提供しないため、ランダムな順序で返されると想定します。

常に最も安全なアプローチをとってください。

たとえば、java HttpServletインターフェース: ServletRequest.html#getParameterValues

getParameterMapメソッドでさえ、パラメーターの順序に関する言及を省略します(java.util.Mapイテレーターの順序も信頼できません)。


3

通常、次のような重複するパラメータ値

http://example.com/page?field=foo&field=bar

配列である単一のqueryStringパラメータになります。

field[0]=='foo'
field[1]=='bar'

ASP、ASP.NET、およびPHP4でこの動作を見てきました。


正確には、これは事実上の標準ですが、私が見る限り、それについての正式な決定はありません。私はこれが事実であるとは思わないので、私はそれを見つけるのにちょうど無能です。
Stefano Borini、

2
はい、おそらく誰もがその振る舞いを見てきました。問題は、それが実際にどこかに指定されているかどうかでした。
ティロ

-1

同じ質問がありました。クエリを解析して文字列化するJavaScript関数を書いています。一部の言語ではこれらの形式がサポートされていますが、クエリ文字列に重複した名前があるか、x [] = 1&x [] = 2などの角かっこ付きの名前が標準であるかどうかはわかりません。

しかし、ChromeとFirefoxには新しいクラスという名前が付けられてURLSeachParamsおり、最も単純な形式のみをサポートしていますname=value。クエリ文字列に重複する名前がある場合、のgetメソッドはURLSearchParams最初の名前のみを返します。

したがって、個人的には、おそらく最も単純で重複する名前のURLがない方が、はるかに安全です。


1
クエリ文字列に重複する名前がある場合、URLSearchParamsのgetメソッドは最初の名前のみを返します。これは不正解です。すべての値を配列として取得できますURLSearchParams.getAll('x')
Blaise

@ブレーズありがとうございます、前に機能を誤解しました。
LCB、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.