1. ホーム
  2. url

[解決済み] URIクエリで何が有効で何が無効なのか?

2022-11-10 12:46:56

質問

背景(さらに下の質問)

私はこれを解読しようとしてRFCとSOの質問を読んで前後にこれをグーグルしてきたが、私はまだジャックを持っていない。

だから、私たちはベストアンサーに投票して、それで終わりなのでしょうか?

基本的にはこれに尽きますね。

3.4. クエリコンポーネント

クエリコンポーネントは、リソースが解釈する情報の文字列です。

query = *uric

クエリ・コンポーネント内では、";", "/", "?", ":", "@", "&", "=", "+", "," および "$" は予約文字に指定されています。

まず最初にモヤモヤするのは、*uricがこのように定義されていることです。

uric = reserved | unreserved | escaped

reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","

しかし、これは次のような段落によって、いくらか明確にされています。

上記の構文クラスのquot;reserved"は、URI内で許可されているが、汎用URI構文の特定のコンポーネント内で許可されていない可能性がある文字を指しています。

reserved"セット内の文字は、すべてのコンテキストで予約されているわけではありません。任意の URI コンポーネント内で実際に予約されている文字のセットは、そのコンポーネントによって定義されます。一般的に、文字は、その文字がエスケープされた US-ASCII エンコーディングで置き換えられると URI のセマンティクスが変化する場合に予約されます。

この最後の抜粋はいくらか後ろ向きな感じがしますが、予約された文字セットはコンテキストに依存することを明確に述べています。しかし、3.4 では、すべての予約文字がクエリ コンポーネント内で予約されていると述べていますが、ここでセマンティクスを変更する唯一のものは、URI がクエリ文字列の概念を定義しないため、クエスチョンマーク (?) をエスケープすることです。

この時点で、私は RFC を完全にあきらめましたが、RFC 1738 が特に興味深いものであることがわかりました。

HTTP URL は次のような形式をとります。

http://<host>:<port>/<path>?<searchpart>

pathコンポーネントとsearchpartコンポーネントでは、"/", ";", "?" は予約されています。HTTP では、階層構造を指定するために "/" 文字が使用されることがあります。

私は、少なくとも HTTP URL に関しては、RFC1738 が RFC2396 よりも優先されると解釈しています。URI クエリにはクエリ文字列の概念がないため、予約済みという解釈は、私が今までに慣れ親しんできたように、クエリ文字列を定義することを本当に許可してくれません。

質問

これは、私が他のリソースのリクエストと一緒に数字のリストを渡したいと思ったときに始まりました。私はそれについてあまり考えず、ただカンマで区切られた値としてそれを渡しました。しかし、驚いたことに、カンマはエスケープされました。クエリ page.html?q=1,2,3 がエンコードされると、次のようになります。 page.html?q=1%2C2%2C3 は動作しますが、醜いので期待しませんでした。そこでRFCを調べ始めたんです。

私の最初の質問は、単純に、カンマのエンコーディングは本当に必要なのでしょうか?

私の答えは、RFC2396によると: イエス、RFC1738によると: ノーです。

その後、リクエスト間のリストの受け渡しに関する関連ポストを見つけました。csv アプローチが悪いと評価されたところです。代わりにこれが表示されました (以前にこれを見たことはありません)。

page.html?q=1;q=2;q=3

2つ目の質問ですが、これは有効なURLなのでしょうか?

私の答えは、RFC2396によると: いいえ、RFC1738によると: いいえ (; は予約済み) です。

私はそれが数字である限り、csvを渡すことに何の問題もありませんが、そうです、カンマが突然他の何かのために必要になった場合、値を前後にエンコードおよびデコードしなければならないというリスクに遭遇します。とにかく、私は ASP.NET でセミコロンのクエリ文字列を試してみましたが、結果は私が期待したものではありませんでした。

Default.aspx?a=1;a=2&b=1&a=3

Request.QueryString["a"] = "1;a=2,3"
Request.QueryString["b"] = "1"

私は、私が "a" を求めると、カンマの入った文字列が得られるので、これがcsvアプローチとどのように大きく異なるかを理解するのに失敗しています。ASP.NETは確かにリファレンス実装ではありませんが、まだ私を失望させたことはありません。

しかし、最も重要なことは--私の3番目の質問--このための仕様はどこにあるのか?

どのように解決するのですか?

ある文字が汎用 URL コンポーネント内で予約されているからといって、コンポーネント内またはコンポーネント内のデータ内に出現したときにその文字をエスケープしなければならないわけではありません。その文字は、汎用またはスキーム固有の構文内で区切り文字として定義されていなければならず、また、その文字の出現はデータ内でなければなりません。

一般的な URI の現在の標準は RFC 3986 であり、これには次のように書かれています。

2.2. 予約文字

URIには、"reserved"セットの文字で区切られたコンポーネントとサブコンポーネントがあります。これらの文字は、一般的な構文、各スキーム固有の構文、または URI の再参照アルゴリズムの実装固有の構文によって区切り文字として定義される(またはされない)ため、"reserved" と呼ばれています。もしURIコンポーネントのデータが が予約文字の区切り文字としての目的に抵触する場合 [強調] となる場合、競合するデータは URI が形成される前にパーセントエンコードされなければなりません。

   reserved = gen-delims / sub-delims (予約文字)

gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" です。

sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";"="

3.3. パスコンポーネント

[...]
pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
[...]

3.4 クエリーコンポーネント

[...]
      query = *( pchar / "/" / "?" )

このように、カンマはクエリ文字列内で明示的に許可されており、特定のスキームがカンマを区切り文字として定義している場合にのみ、データ内でエスケープする必要があります。HTTP スキームでは、カンマやセミコロンをクエリ文字列の区切り記号として使用しないため、エスケープする必要はありません。ブラウザがこの標準に従うかどうかは別の問題です。

CSVの標準的な規則に従って、データを引用するか、バックスラッシュでカンマをエスケープすればよいのです。

RFC2396に関しては、HTTPクエリ文字列の中でエスケープされていないカンマも許容しています。

2.2. 予約文字

多くのURIは、特定の特殊文字で構成される、またはそれによって区切られるコンポーネントを含んでいます。 特別な文字があります。 これらの文字は、URI コンポーネント内での使用が予約された文字に限定されるため、quot;reserved" と呼ばれます。 と呼ばれ、URI コンポーネント内での使用はその予約された目的に限定されるからです。 と呼ばれます。 URIコンポーネントのデータが予約された目的に抵触する場合、抵触するデータは予約された目的から削除されます。 URIコンポーネントのデータが予約された目的と衝突する場合、衝突するデータはURIを形成する前にエスケープされなければなりません。 URIを形成する前にエスケープされなければなりません。

カンマは HTTP スキームにおいて予約された目的を持っていないので、データにおいてエスケープされる必要はありません。予約された文字がパーセントエンコードされたときにセマンティクスを変更する文字であるという 2.3 節の注意は、一般的にのみ適用されます。