何が有効で、URIクエリにないものは何ですか?


99

背景(質問はさらに下)

私はこれを何度もグーグルで調べて、RFCとSOの質問を読んでこれを解こうとしましたが、それでもジャックはありません。

だから、私たちは「最良の」答えに投票するだけだと思います、それだけですか?

基本的には、これに要約されます。

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

クエリコンポーネントは、リソースによって解釈される情報の文字列です。

query = *uric

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

最初に私を驚かせることは* uricがこのように定義されていることです

uric = reserved | unreserved | escaped

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

ただし、これは次のような段落でいくらか明確になります。

上記の「予約済み」構文クラスは、URI内では許可されているが、汎用URI構文の特定のコンポーネント内では許可されていない可能性がある文字を指します。これらは、セクション3で説明するコンポーネントの区切り文字として使用されます。

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

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

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

HTTP URLの形式は次のとおりです。

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

<path>および<searchpart>コンポーネント内で、「/」、「;」、「?」予約されています。"/"文字は、階層構造を指定するためにHTTP内で使用できます。

私はこれを、RFC 1738がRFC 2396に取って代わるHTTP URLに関して少なくとも解釈します。URIクエリにはクエリ文字列の概念がないため、予約済みの解釈では、慣れているクエリ文字列を定義できません。今までにやっている。

質問

これはすべて、別のリソースのリクエストとともに数値のリストを渡したいときに始まりました。私はそれについてはあまり考えず、コンマ区切りの値として渡しただけです。驚いたことに、コンマはエスケープされました。page.html?q=1,2,3エンコードされたクエリは機能しますpage.html?q=1%2C2%2C3が、醜く、期待していませんでした。それは私がRFCを通過し始めたときです。

私の最初の質問は単純です、コンマのエンコードは本当に必要ですか?

RFC 2396によると私の答え:はい、RFC 1738によると:いいえ

後で、リクエスト間のリストの受け渡しに関する関連記事を見つけました。csvアプローチが悪いとして準備されていたところ。代わりにこれが表示されました(これを見たことがない)。

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

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

RFC 2396による私の回答:いいえ、RFC 1738による:いいえ(;予約済み)

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

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

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

これがcsvアプローチと大きく異なる点を確認できません。「a」を要求すると、コンマを含む文字列が返されます。ASP.NETは確かにリファレンス実装ではありませんが、まだ失望していません。

しかし、最も重要なのは-私の3番目の質問-これの仕様はどこにあるのですか?そして、あなたは何をしますか?


RFC 2396がほぼ4年後に発行されたとき、RFC 1738はどのようにしてRFC 2396に取って代わることができますか?
Matthew Flaschen

1
URLと実際に意味のあることに関しては、それが私の解釈です。(supersedeはおそらく正しい言葉ではありませんが、RFC用語で古いRFCを廃止するために使用されているため、RFC 1738は、検索部分にクエリ文字列を置くことができる唯一の仕様である場合、廃止されたとは感じていませんURL)
John Leidegren

回答:


68

文字が汎用URLコンポーネント内で予約されているということは、コンポーネント内またはコンポーネント内のデータ内に出現するときにエスケープする必要があるという意味ではありません。文字は、ジェネリックまたはスキーム固有の構文内の区切り文字としても定義する必要があり、文字の外観はデータ内にある必要があります。

汎用URIの現在の標準はRFC 3986で、これは次のように述べています。

2.2。予約文字

URIには、「予約済み」セットの文字で区切られたコンポーネントとサブコンポーネントが含まれます。これらの文字は、一般的な構文、各スキーマ固有の構文、またはURIの逆参照アルゴリズムの実装固有の構文によって区切り文字として定義される場合とされない場合があるため、「予約済み」と呼ばれます。URIコンポーネントのデータが、区切り文字としての予約文字の目的競合する場合(強調を追加)、URIが形成される前に競合するデータをパーセントエンコードする必要があります。

   予約済み= gen-delims / sub-delims

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

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

3.3。パスコンポーネント

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

3.4クエリコンポーネント

[...]
      クエリ= *(pchar / "/" / "?")

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

文字列データの場合、CSVを使用すると問題なく機能します。標準のCSV規則に従ってデータを引用するか、バックスラッシュでコンマをエスケープする必要があります。

RFC 2396と同様に、HTTPクエリ文字列でエスケープされていないコンマも許可されます。

2.2。予約文字

多くのURIには、特定の特殊文字で構成されている、または特定の特殊文字で区切られたコンポーネントが含まれています。これらの文字は、URIコンポーネント内での使用が予約された目的に限定されているため、「予約済み」と呼ばれます。URIコンポーネントのデータが予約済みの目的と競合する場合は、URIを形成する前に競合するデータをエスケープする必要があります。

コンマはHTTPスキームでは予約された目的を持っていないため、データ内でエスケープする必要はありません。2.3からの予約文字に関する注記は、パーセントエンコードが一般的にのみ適用される場合にセマンティクスを変更する文字です。文字は、特定のスキームのセマンティクスを変更せずにパーセントでエンコードされていても、予約されている場合があります。


23

クエリ文字列で有効なものに答えるために、リクエストを作成するときにChromeで置き換えられる特殊文字を確認しました。

Space -> %20
! -> !
" -> %22
# -> removed, marks the end of the query string
% -> %
& -> &
' -> %27
( -> (
) -> )
* -> *
+ -> + (this usually means blank when received at the server, so encode if necessary)
, -> ,
- -> -
. -> .
/ -> /
: -> :
; -> ;
< -> %3C
= -> =
> -> %3E
? -> ?
@ -> @
[ -> [
\ -> \
] -> ]
^ -> ^
_ -> _
` -> `
{ -> {
| -> |
} -> }
~ -> ~

Extended ASCII (like °) -> Every character from this set is encoded

注:これはおそらく、リンクのURIを生成するときに置き換えられなかった文字をエスケープしてはいけないという意味ではありません。たとえば~、互換性の問題があるため、URIで使用しないことをお勧めしますが、それでも有効な文字です。

別の例としては、有効なプラス記号がありますが、サーバーがリクエストの一部として受け取った場合、通常はエンコードされた空白として扱われます。したがって、スペースではなくプラスを表すことが目的である場合に有効であっても、エンコードする必要があります。

エンコードする必要があるものに答えるために:無効な文字、および文字どおりに処理したいが特別な意味を持つ文字、またはサーバー側で問題を引き起こす可能性がある文字。


ある/programming/2366260/whats-valid-and-whats-not-in-a-uri-query?param=b#1;c#2有効なクエリパラメータは?
Sumit Jain

@SumitJainいいえ、そのまま#ではURIのクエリ部分内に表示できないため。としてエンコードする必要がある%23ため、URIはにする必要があります/programming/2366260/whats-valid-and-whats-not-in-a-uri-query?param=b%231;c%232

10

使うだけ ?q=1+2+3

私はここで4番目の質問に答えています:)質問しませんでしたが、すべては次のように始まりました。私には、最良の方法は、スペースで区切られたパスを渡すことです。スペースはurl-form-encodedに変換され+ます。リスト内の値にスペースが含まれていないことがわかっている限り、うまく機能します(数字では使用されない傾向があるもの)。


これはコメントであるはずですが(質問には回答しません)、ありがとうございます。+私がコンマを使用しようとしていた特定のケースではさらに意味があります。
Gajus

6

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

これは有効なURLですか?

はい。;ではなくRFCによって、予約されています。このコンポーネントを定義するコンテキストapplication/x-www-form-urlencodedは、HTML標準の一部であるメディアタイプの定義です(セクション17.13.4.1)。特に、セクションB.2.2に隠された卑劣なノート:

HTTPサーバーの実装者、特にCGIの実装者が「;」の使用をサポートすることをお勧めします。"&"の代わりに使用して、この方法で "&"文字をエスケープする手間を省きます。

残念ながら、ASP.NETを含む多くの一般的なサーバー側スクリプトフレームワークは、この使用法をサポートしていません。


したがって、?q=1;q=2;q=3クエリは有効ですがあいまいです。つまり、一部のサーバー側フレームワークは意味を読み取って{ q: '1;q=2;q=3' }、他のフレームワークはと同じように解釈する場合があります{ q: {'1', '2', '3'}}
Nas Banov 2014

1
はい。さらに悪いことに、HTML5にはに関する言語が含まれていないため、;HTML4とHTML5に一貫性がありません。Ugh、スペックドキュメントでの非規範的な言語の危険...
bobince 14

@NasBanovそしてさらに他の人(例えばPHP)はそれを次のように解釈します{ q: 3 }
ニコラスシャンクス

1
@NicholasShanks-PHPが関与している場合、すべての賭けはオフです!:)
Nas Banov 2017

1

それに注意したい page.html?q=1&q=2&q=3も有効なURLです。これは、クエリ文字列で配列を表現する完全に正当な方法です。それがどのように提示されるかは、サーバーテクノロジーによって決まります。

クラシックASPでは、チェックResponse.QueryString("q").Countしてから使用しますResponse.QueryString("q")(0)(および(1)と(2))。

ASP.NETでもこれを確認したことに注意してください(意図したものではないと思いますが、見てください)。

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

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

セミコロンは無視されるので、a2回定義し、その値をコンマで区切って2回取得したことに注意してください。すべてのアンパサンドDefault.aspx?a=1&a=2&b=1&a=3を使用するとa、 "1,2,3"になります。しかし、要素自体にコンマが含まれている場合に備えて、各要素を取得する方法があると確信しています。これは、サブ値とコンマ区切り文字を連結する、インデックス付けされていないQueryStringのデフォルトプロパティです。


1

同じ問題がありました。ハイパーリンクされたURLはサードパーティのURLであり、形式page.html?q=1,2,3のみのパラメーターのリストを予期していましたが、URL page.html?q=1%2C2%2C3は機能しませんでした。私はそれをjavascriptを使用して動作させることができました。最善の方法とは言えないかもしれませんが、誰かに役立つ場合は、ここでソリューションを確認できます。


-3

エンコードされた文字をFLASH / SWFファイルに送信する場合は、文字を2回エンコードする必要があります!! (Flashパーサーのため)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.