web-dev-qa-db-ja.com

URLからURIへのエンコードにより、「%3D」が「%253D」に変更されます

URLをURIにエンコードするのに問題があります。

mUrl = "A string url that needs to be encoded for use in a new HttpGet()";
URL url = new URL(mUrl);
URI uri = new URI(url.getProtocol(), url.getAuthority(), url.getPath(), 
    url.getQuery(), null);

これは、次のURLに対して私が期待することを行いません。

文字列を渡す:

http://m.bloomingdales.com/img?url=http%3A%2F%2Fimages.bloomingdales.com%2Fis%2Fimage%2FBLM %2Fproducts%2F3%2Foptimized%2F1140443_fpx.tif%3Fwid%3D52%26qlt%3D90%2C0%26layer%3Dcomp%26op_sharpen%3D0%26resMode%3Dsharp2%26op_usm%3D0.7%2C1.0%2C0.5%t2C0%26 %3Djpeg&ttl = 30d

次のようになります:

http://m.bloomingdales.com/img?url=http%253A%252F%252Fimages.bloomingdales.com%252Fis%252Fimage%252FBLM %252Fproducts%252F3%252Foptimized%252F1140443_fpx.tif%253Fwid%253D52%2526qlt%253D90%252C0%2526layer%253Dcomp%2526op_sharpen%253D0%2526resMode%253Dsharp2%2526op_usm%253D0.7%252C1.0%252C0.5%t%252C0.5%t252c0.5%252C1.0%2520.50.5 %253Djpeg&ttl = 30d

壊れています。たとえば、%3D%253Dに変換されます。文字列に既に含まれている%に不思議なことをしているようです。

何が起こっているのですか、ここで何が間違っているのですか?

13
cottonBallPaws

最初に(エスケープされた)文字列をURLクラスに入れます。それは何もエスケープしません。次に、URLのセクションを引き出します。これにより、何も処理せずにセクションが返されます(そのため、それらを配置したときにエスケープされていたため、エスケープされています)。最後に、 マルチ引数コンストラクタ を使用して、セクションをURIクラスに配置します。このコンストラクタは、パーセンテージを使用してURIコンポーネントをエンコードするように指定されています。

したがって、たとえば、「:」が「%3A」(良好)になり、「%3A」が「%253A」(不良)になるのは、この最後のステップです。 。すでにエンコードされているURLを入力しているため*、再度エンコードする必要はありません。

したがって、URIの-​​ 単一引数コンストラクタ はあなたの友達です。何もエスケープせず、事前にエスケープされた文字列を渡す必要があります。したがって、URLはまったく必要ありません。

mUrl = "A string url is already percent-encoded for use in a new HttpGet()";
URI uri = new URI(mUrl);

*唯一の問題は、URLがパーセントでエンコードされていない場合と、そうでない場合があります。次に、より大きな問題があります。プログラムが常にエンコードされているURLで開始するのか、エンコードが必要なURLで開始するのかを決定する必要があります。

パーセントエンコードされていない完全なURLとしてそのようなことはありませんがあることに注意してください。たとえば、完全なURL "http://example.com/bob&co"を取得して、どういうわけかそれを適切にエンコードされたURL "http://example.com/bob%26co"に変換することはできません。エスケープする必要があります)と文字(どちらにする必要がありますか)?これが、URIの単一引数形式では、文字列がすでにエスケープされている必要がある理由です。エスケープされていない文字列がある場合は、パーセントエンコードする必要がありますbefore完全なURL構文に挿入します。これが、URIの複数引数コンストラクターが役立ちます。

編集:元のコードがフラグメントを破棄するという事実を見逃しました。 URLのフラグメント(またはその他の部分)を削除する場合は、上記のようにURIを作成し、必要に応じてすべての部分を引き出します(これらはdecodedになります)。通常の文字列に)、次にそれらをURIマルチ引数コンストラクターに戻します(URIコンポーネントとしてre-encodedになります):

uri = new URI(uri.getScheme(), uri.getUserInfo(), uri.getHost(), uri.getPort(),
              uri.getPath(), uri.getQuery(), null)  // Remove fragment
30
mgiuca

%3d手段-> =(等しい)

そして

%253D-> =(Equal)10進数6hex(バイト)3D

%253D CGIの16進インジケータ:%3D

5
Sarat Patel

URLクラスは、URLを解析したときに%シーケンスをデコードしませんでしたが、URIクラスはそれらを(再度)エンコードしています。 URIを使用して、URL文字列を解析します。

Javadocs:

http://download.Oracle.com/javase/6/docs/api/Java/net/URL.html

RFC2396で定義されているエスケープメカニズムに従って、URLクラス自体はURLコンポーネントをエンコードまたはデコードしません 。 URLを呼び出す前にエスケープする必要があるフィールドをエンコードし、URLから返されたエスケープされたフィールドをデコードすることは、呼び出し元の責任です。さらに、URLにはURLエスケープの知識がないため、同じURLのエンコードされた形式とデコードされた形式の等価性は認識されません。たとえば、次の2つのURL:

http://foo.com/hello world/ and http://foo.com/hello%20world

互いに等しくないと見なされます。 URIクラスは、特定の状況でコンポーネントフィールドのエスケープを実行することに注意してください。

URLのエンコードとデコードを管理するための推奨される方法は、URIを使用して、これら2つのクラスは、toURI()とURI.toURL()を使用しています。

4
Bert F