11

hrefURIを生成する必要があります。パーセントエンコーディングが必要な予約文字を除いて、すべて簡単です。たとえば、へのリンクは次の/some/path;elementように表示されます(単一のエンティティを表す<a href="/some/path%3Belement">ことはわかっています)。path;element

最初はこれを行う Java ライブラリを探していましたが、自分で何かを書くことになりました (この質問は Java 固有ではないため、Java で失敗したものについては以下を参照してください)。

したがって、RFC 3986は、いつエンコードしないかを提案しています。私が読んだように、これは、キャラクターがunreserved (ALPHA / DIGIT / "-" / "." / "_" / "~")クラスに分類されるときに発生するはずです。ここまでは順調ですね。しかし、逆の場合はどうでしょうか。%RFC では、パーセント ( ) は常にエンコードが必要であるとのみ言及されています。しかし、他の人はどうですか?

質問:予約されていないものはすべて、パーセントでエンコードできる/すべきであると仮定するのは正しいですか? たとえば、左大括弧(は必ずしもエンコードする必要はありませんが、セミコロンは必要です;/firstエンコードしないと、次のときに *を探すことになります<a href="/first;second">。しかし、次のよう<a href="/first(second">にすると、予想どおり、常に を探してしまい/first(secondます。私を混乱させているのは、RFC に関する限り、 と の両方が同じクラス(;あるということです。sub-delims私が想像するように、予約されていないものすべてをエンコードすることは安全な賭けですが、ローカライズされた URI に関しては、SEO 性、ユーザー フレンドリ性についてはどうでしょうか?

さて、Java ライブラリで何が失敗したか。私はそれをやってみまし
new java.net.URI("http", "site", "/pa;th", null).toASCIISTring()
たが、これhttp://site/pa;thは良くありません。同様の結果が観察されました:

  • javax.ws.rs.core.UriBuilder
  • Spring の UriUtils - 私は両方を試しましencodePath(String, String)encodePathSegment(String, String)

[*]をクリックしたときにサーバー側/firstで呼び出した結果ですHttpServletRequest.getServletPath()<a href="/first;second">

編集:おそらく、この動作は Tomcat で観察されたことに言及する必要があります。また、Tomcat 6 と 7 の両方が同じように動作することを確認しました。

4

2 に答える 2

5

予約されていないものはすべて、パーセントでエンコードできる/すべきであると仮定するのは正しいですか?

いいえ。RFC 3986 は次のように述べています。

「通常の状況では、URI 内のオクテットがパーセントでエンコードされるのは、コンポーネント パーツから URI を生成するプロセス中だけです。これは、サブコンポーネントの区切り文字として使用する予約文字と、どの文字を使用するかを実装が決定するときです。データとして安全に使用できます。」

つまり、コンテキストに応じて、どの区切り文字 (つまり、<delimiter>文字) をエンコードする必要があるかを決定するということです。エンコードする必要のないものはエンコードしないでください。

たとえば/、a がパス コンポーネントに表示される場合はパーセント エンコードしないでください。ただし、クエリまたはフラグメントに表示される場合はパーセント エンコードする必要があります。

したがって、実際には、;文字 (のメンバーである文字は、<reserved>自動的にパーセント エンコードされるべきではありません。実際、Java URL および URI クラスはこれを行いません。URI(...) javadoc、具体的には手順 7 を参照してください)<path>コンポーネントが処理されます。

これは、次の段落によって強化されます。

「予約文字の目的は、URI 内の他のデータと区別できる一連の区切り文字を提供することです。対応するパーセントでエンコードされたオクテットによる予約文字の置換が異なる URI は同等ではありません。予約済みのパーセント エンコード文字、または予約文字に対応するパーセントでエンコードされたオクテットをデコードすると、URI がほとんどのアプリケーションでどのように解釈されるかが変わります. したがって、予約セットの文字は正規化から保護されているため、スキーム固有およびURI 内のデータ サブコンポーネントを区切るためのプロデューサー固有のアルゴリズム。」

したがって、これは、パーセントでエンコードさ;れた を含む URL は、raw を含む URL と同じではないことを示しています;。そして最後の文は、自動的にパーセントでエンコードまたはデコードされるべきではないことを暗示しています。


疑問が残ります - なぜパーセントでエンコードしたいのですか? ;

人々が任意のパスを持つ任意のページを作成できる CMS があるとします。後で、サイト マップ コンポーネントなどのすべてのページへの href リンクを生成する必要があります。したがって、どの文字をエスケープするかを知るアルゴリズムが必要です。この場合、セミコロンは文字どおりに扱う必要があり、エスケープする必要があります。

申し訳ありませんが、セミコロンをエスケープする必要はありません。

URL / URI 仕様に関する限り、 に;特別な意味はありません。特定の Web サーバー / Web サイトにとって特別な意味を持つ場合もありますが、一般的には(つまり、そのサイトに関する特定の知識がなければ)、これを知る方法はありません。

  • が特定の URI で特別な意味を持っている場合;、それをパーセント エスケープすると、その意味が壊れます。たとえば、サイトが;セッショントークンをパスに追加できるようにするために使用している場合、パーセントエンコーディングはセッショントークンの認識を停止します...

  • が単にクライアントから提供されたデータ文字である場合;、それをパーセント エンコードすると、URI の意味が変わる可能性があります。これが重要かどうかは、サーバーの機能によって異なります。つまり、アプリケーション ロジックの一部としてデコードするかどうか。

これが意味すること 「正しいこと」を知るには、URI がエンド ユーザーやサイトにとって何を意味するかについての詳細な知識が必要です。これを実装するには、高度な読心術技術が必要です。私のお勧めは、CMS が URI パスの区切り文字をソフトウェアに配信するに適切にエスケープすることで、CMS に解決させることです。アルゴリズムは必然的に、CMS とコンテンツ配信プラットフォームに固有のものになります。URL で識別されるドキュメントの要求に応答し、それらを解釈する方法を知る必要があります。

(任意のパスを使用する任意の人々をサポートすることは、少しクレイジーです。いくつかの制限が必要です。たとえば、Windows でさえ、ファイル名コンポーネントでファイル区切り文字を使用することは許可されていません。したがって、どこかに境界を設ける必要があります。それらがどこにあるべきかを決めるだけの問題です。)

于 2011-05-16T13:10:53.703 に答える
2

絶対パス部分のABNF :

 path-absolute = "/" [ segment-nz *( "/" segment ) ]
 segment       = *pchar
 segment-nz    = 1*pchar
 pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
 pct-encoded   = "%" HEXDIG HEXDIG
 unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
 reserved      = gen-delims / sub-delims
 sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
               / "*" / "+" / "," / ";" / "="

pcharサブデリムが含まれているため、パス部分でこれらをエンコードする必要はありません。:@-._~!$&'()*+,;=

パスのエンコーダーを含む独自の URL ビルダーを作成しました。いつものように、 emptorに注意してください。

于 2011-05-06T16:12:49.340 に答える