web-dev-qa-db-ja.com

有効なものとURIクエリにないもの

背景(さらに下の質問)

私は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クエリにはクエリ文字列の概念がないため、reservedの解釈では実際にクエリ文字列を定義することはできません。今ではやっています。

質問

これはすべて、別のリソースのリクエストと一緒に数字のリストを渡したいときに始まりました。私はそれについてあまり考えず、コンマ区切りの値として渡しました。驚いたことに、コンマはエスケープされました。クエリ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"

"a"を要求すると、コンマを含む文字列が取得されるため、これがcsvアプローチとどのように大きく異なるかはわかりません。 ASP.NETは確かに参照実装ではありませんが、まだ私を失望させていません。

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

90
John Leidegren

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

ジェネリックURIの現在の標準は RFC 3986 です。

2.2。予約文字

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

   reserved = gen-delims/sub-delims 
 
 gen-delims = ":"/"/"/"?"/"#"/"["/"]"/"@" 
 
 sub-delims = "!"/"$"/"&"/"'"/"("/")" 
/"*"/"+"/"、"/";"/"="

.3。パスコンポーネント

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

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

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

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

CSVを使用すると、文字列データに対して正常に機能するはずです。標準のCSV規則に従い、データを引用するか、バックスラッシュでコンマをエスケープする必要があります。

RFC 2396に関しては、HTTPクエリ文字列にエスケープなしのカンマも使用できます。

2.2。予約文字

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

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

64
outis

クエリ文字列で有効なものに答えるために、リクエスト時に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で~を使用しないことが推奨されることがよくありますが、それでも有効な文字です。

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

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

18
user764754

?q=1+2+3を使用するだけです

私はここで4番目の質問に答えています:)それは尋ねませんでしたが、すべてで始まりました:どのように数字のリストをコンマ区切り値で渡しますか?私にとって最良のアプローチは、スペースで区切られたものを渡すことです。スペースはurl-form-encodeで+にエンコードされます。リスト内の値にスペースが含まれていないことがわかっている限り、うまく機能します(数字はそうではない傾向があります)。

10
Nas Banov

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を含む多くの一般的なサーバー側スクリプトフレームワークは、この使用法をサポートしていません。

6
bobince

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

Classic 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"
_

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

1
ErikE

同じ問題がありました。ハイパーリンクされたURLはサードパーティのURLであり、page.html?q=1,2,3のみおよびURL page.html?q=1%2C2%2C3 動作しませんでした。 javascriptを使用して動作させることができました。最善のアプローチではないかもしれませんが、ソリューションを確認できます here それが誰かを助けるなら。

1
slash