JavaでのHTTP URLアドレスエンコーディング


366

私のJavaスタンドアロンアプリケーションは、ユーザーからURL(ファイルを指す)を取得し、それをヒットしてダウンロードする必要があります。私が直面している問題は、HTTP URLアドレスを適切にエンコードできないことです...

例:

URL:  http://search.barnesandnoble.com/booksearch/first book.pdf

java.net.URLEncoder.encode(url.toString(), "ISO-8859-1");

私を返します:

http%3A%2F%2Fsearch.barnesandnoble.com%2Fbooksearch%2Ffirst+book.pdf

しかし、私が欲しいのは

http://search.barnesandnoble.com/booksearch/first%20book.pdf

(スペースは%20に置き換えられました)

URLEncoderHTTP URLをエンコードするようには設計されていないと思います... JavaDocは「HTMLフォームエンコーディングのユーティリティクラス」と言っています...これを行う他の方法はありますか?



動作は完全に正しいです。URLエンコードとは、何かをURLパラメータとして安全に渡すことができる文字列に変換することで、URLとしてはまったく解釈されません。一方、URLの1つの小さな部分だけを変換する必要があります。
スティーブンホルト2017年

回答:


303

java.net.URIのクラスは助けることができます。あなたが見つけたURLのドキュメントで

URIクラスは、特定の状況でコンポーネントフィールドのエスケープを実行することに注意してください。URLのエンコードとデコードを管理するための推奨される方法は、URIを使用することです

次のように、複数の引数を持つコンストラクタの1つを使用します。

URI uri = new URI(
    "http", 
    "search.barnesandnoble.com", 
    "/booksearch/first book.pdf",
    null);
URL url = uri.toURL();
//or String request = uri.toString();

(URIの単一引数コンストラクターは無効な文字をエスケープしません)


上記のコードでは、不正な文字のみがエスケープされます。非ASCII文字はエスケープされません(fatihのコメントを参照)。
このtoASCIIStringメソッドを使用して、US-ASCII文字のみを含む文字列を取得できます。

URI uri = new URI(
    "http", 
    "search.barnesandnoble.com", 
    "/booksearch/é",
    null);
String request = uri.toASCIIString();

のようなクエリを含むURLの場合、http://www.google.com/ig/api?weather=São Pauloコンストラクタの5パラメータバージョンを使用します。

URI uri = new URI(
        "http", 
        "www.google.com", 
        "/ig/api",
        "weather=São Paulo",
        null);
String request = uri.toASCIIString();

13
ここで言及するURIクラスは、「java.net」ではなく「org.apache.commons.httpclient.URI」からのものであり、「java.net」はURIで不正な文字を受け入れません。以下のマットコメントで言及されている方法のように、そのコンポーネントからURLを構築するコンストラクタ
Mohamed Faramawi

7
@Mohamed:私が言及し、テストに実際に 使用したクラスは、次のとおりjava.net.URIです。完全に動作しました(Java 1.6)。完全修飾クラス名は、それが標準のJavaの名前ではなく、リンクがのドキュメントを指している場合に言及しjava.net.URIます。そして、Sudhakarのコメントにより、「コモンズライブラリ」を含めずに問題を解決しました!
user85421 2010年

1
URI uri = new URI( "http"、 "search.barnesandnoble.com"、 "/ booksearch /é"、null); このサンプルでは正しいエスケープを行わないのですか?これは%エスケープでエスケープされているはずです
fmucar '19年

@fatih-そうです、ありがとう!通常それは問題にはならないはずですが、簡単な解決策があります-以前に書いたのとほとんど同じです。2番目の編集を参照してください。
user85421 '19年

編集のための@Carlos Thx。現在はエスケープしますが、エスケープは正しくありません。Path paramsのcharのHEX値に%を追加する必要があります。
つまり、échar

91

上記の回答のほとんどが正しくないことに注意してください。

URLEncoderクラスには、名前があるにもかかわらず、ここにする必要があるものではありません。残念なことに、Sunがこのクラスにそれほど迷惑な名前を付けました。 URLEncoderパラメータ自体としてデータを渡すためのものであり、URL自体をエンコードするためのものではありません。

つまり、"http://search.barnesandnoble.com/booksearch/first book.pdf"URLです。パラメータは、たとえばです"http://search.barnesandnoble.com/booksearch/first book.pdf?parameter1=this&param2=that"。パラメータは、使用するものですURLEncoder

次の2つの例は、2つの違いを示しています。

以下は、HTTP標準に従って、誤ったパラメーターを生成します。アンパサンド(&)とプラス(+)が正しくエンコードされていないことに注意してください。

uri = new URI("http", null, "www.google.com", 80, 
"/help/me/book name+me/", "MY CRZY QUERY! +&+ :)", null);

// URI: http://www.google.com:80/help/me/book%20name+me/?MY%20CRZY%20QUERY!%20+&+%20:)

以下は、クエリが適切にエンコードされた正しいパラメータを生成します。スペース、アンパサンド、プラス記号に注意してください。

uri = new URI("http", null, "www.google.com", 80, "/help/me/book name+me/", URLEncoder.encode("MY CRZY QUERY! +&+ :)", "UTF-8"), null);

// URI: http://www.google.com:80/help/me/book%20name+me/?MY+CRZY+QUERY%2521+%252B%2526%252B+%253A%2529

2
そうです、ドキュメントdocs.oracle.com/javase/1.4.2/docs/api/java/net/…、java.lang.String、java.lang.String、intによれば、URIコンストラクタはすでにクエリ文字列をエンコードしています。 、java.lang.String、java.lang.String、java.lang.String)
12

8
@Draemon答えは正しいですが、クエリ文字列を一般的ではない方法で使用しています。より一般的な例は次のとおりですquery = URLEncoder.encode(key) + "=" + URLEncoder.encode(value)。ドキュメントは単に「正当なURI文字ではない文字は引用符で囲まれている」と述べています。
tc。

1
ここでマットに同意します。ブラウザに「google.com/help/me/book name + me /?MY CRZY QUERY!+&+ :)」と入力すると、スペースが自動的にエンコードされますが、クエリ値として「&」が使用されますセパレータと「+」は失われます。
arcot 2014年

80

ここでは、Androidユーザー向けの提案を1つ追加します。これを行うと、外部ライブラリを取得する必要がなくなります。また、上記の回答の一部で提案されているすべての検索/置換文字ソリューションは危険であり、回避する必要があります。

これを試してみてください:

String urlStr = "http://abc.dev.domain.com/0007AC/ads/800x480 15sec h.264.mp4";
URL url = new URL(urlStr);
URI uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef());
url = uri.toURL();

この特定のURLでは、リクエストに使用できるように、これらのスペースをエンコードする必要があることがわかります。

これは、Androidクラスで利用できるいくつかの機能を利用します。まず、URLクラスはURLを適切なコンポーネントに分割できるため、文字列の検索/置換作業を行う必要はありません。次に、このアプローチは、単一の文字列からではなくコンポーネントを介してURIを構築するときに、コンポーネントを適切にエスケープするURIクラス機能を利用します。

このアプローチの優れた点は、有効なURL文字列を取得して、特別な知識を必要とせずに機能させることができることです。


3
素晴らしいアプローチですが、このコードは二重エンコードを妨げないことを指摘したいと思います。たとえば、%20は%2520にエンコードされました。スコットの答えはこれに悩まされていません。
nattster 2014

2
扱えません#
Alston、2014年

または、パスを引用したい場合は、新しいURI(null、null、 "/ path with space"、null、null).toString()
user1050755

1
@Stallmanファイル名に#が含まれている場合、URLクラスはそれを「ref」に入れます(URIクラスの「フラグメント」に相当)。URL.getRef()がパスの一部として扱われる可能性があるものを返すかどうかを検出し、URL.getPath()+ "#" + URL.getRef()を「パス」パラメーターとして、nullを「フラグメント」として渡すことができます"URIクラス7パラメータコンストラクタのパラメータ。デフォルトでは、#の後の文字列は参照(またはアンカー)として扱われます。
gouessej

49

私が開発したソリューションで、他のどのソリューションよりもはるかに安定しています:

public class URLParamEncoder {

    public static String encode(String input) {
        StringBuilder resultStr = new StringBuilder();
        for (char ch : input.toCharArray()) {
            if (isUnsafe(ch)) {
                resultStr.append('%');
                resultStr.append(toHex(ch / 16));
                resultStr.append(toHex(ch % 16));
            } else {
                resultStr.append(ch);
            }
        }
        return resultStr.toString();
    }

    private static char toHex(int ch) {
        return (char) (ch < 10 ? '0' + ch : 'A' + ch - 10);
    }

    private static boolean isUnsafe(char ch) {
        if (ch > 128 || ch < 0)
            return true;
        return " %$&+,/:;=?@<>#%".indexOf(ch) >= 0;
    }

}

3
また、URLを分割する必要があります。コンピュータがURLのどの部分をエンコードするかを知る方法はありません。私の上記の編集を参照してください
fmucar

4
@fmucarそのコードの一部をありがとう!これはUTF-8ではないことに注意してください。UTF-8を取得するには、String utf8Input = new String(Charset.forName("UTF-8").encode(input).array());ここから取得し)入力を前処理するだけです
letmaik

1
このソリューションでは、実際に「http://」部分を「http%3A%2F%2F」にエンコードします。これは、最初の質問で回避しようとしたものです。
Benjamin Piette 2013年

2
URL全体ではなく、エンコードする必要のあるものだけを渡します。URL文字列全体を渡して正しいエンコーディングを期待する方法はありません。すべての場合において、URLを論理的な部分に分割する必要があります。
fmucar 2013年

2
安全ではない文字をUTF-8にエンコードしないため、この回答に問題がありました。ただし、ピアアプリケーションに依存している可能性があります。
Tarnschaf 2013年

36

URLがある場合は、url.toString()をこのメソッドに渡すことができます。二重エンコードを回避するために最初にデコードします(たとえば、スペースをエンコードすると%20が発生し、パーセント記号をエンコードすると%25が発生するため、ダブルエンコードを行うとスペースが%2520になります)。次に、上記のようにURIを使用し、URLのすべての部分を追加します(クエリパラメータを削除しないようにします)。

public URL convertToURLEscapingIllegalCharacters(String string){
    try {
        String decodedURL = URLDecoder.decode(string, "UTF-8");
        URL url = new URL(decodedURL);
        URI uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef()); 
        return uri.toURL(); 
    } catch (Exception ex) {
        ex.printStackTrace();
        return null;
    }
}

1
文字列を「google.co.in/search?q=123%!123」として渡すと、URLDecoder.decode(string、 "UTF-8")はIllegalArgumentExceptionで失敗します。これは有効なURLです。エンコード文字の代わりに%をデータとして使用すると、このAPIは機能しないと思います。
MediumOne、2015年

26

うん、URLエンコードはその文字列をエンコードして、URLで最終的な宛先に正しく渡されるようにします。たとえば、http://stackoverflow.com?url=http://yyy.comにすることはできません。パラメータをUrlEncodingすると、そのパラメータ値が修正されます。

したがって、私には2つの選択肢があります。

  1. ドメインとは別のパスにアクセスできますか?もしそうなら、あなたは単にパスをUrlEncodeすることができるかもしれません。ただし、これが当てはまらない場合は、オプション2が適しています。

  2. commons-httpclient-3.1を取得します。これにはURIUtilクラスがあります。

    System.out.println(URIUtil.encodePath( " http://example.com/x y"、 "ISO-8859-1"));

これは、URIのパス部分のみをエンコードするため、探しているものを正確に出力します。

参考までに、このメソッドを実行時に機能させるには、commons-codecとcommons-loggingが必要です。


Sidenote apache commonsは、4.xブランチでのURIUtilの維持をやめ、JDKのURIクラスを使用することを推奨しているようです。自分で文字列を分割する必要があるという意味です。
ニコリ2014

2)正確に、それはまた、ここで提案されてstackoverflow.com/questions/5330104/... Iも使用URIUtilソリューション
にKraの


11

残念ながら、org.apache.commons.httpclient.util.URIUtilは非推奨であり、replacement org.apache.commons.codec.net.URLCodec実際のURLではなくフォーム投稿に適したコーディングを行います。したがって、単一のコンポーネントを実行する独自の関数を記述する必要がありました(?と&を持つクエリ文字列全体には適していません)。

public static String encodeURLComponent(final String s)
{
  if (s == null)
  {
    return "";
  }

  final StringBuilder sb = new StringBuilder();

  try
  {
    for (int i = 0; i < s.length(); i++)
    {
      final char c = s.charAt(i);

      if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) ||
          ((c >= '0') && (c <= '9')) ||
          (c == '-') ||  (c == '.')  || (c == '_') || (c == '~'))
      {
        sb.append(c);
      }
      else
      {
        final byte[] bytes = ("" + c).getBytes("UTF-8");

        for (byte b : bytes)
        {
          sb.append('%');

          int upper = (((int) b) >> 4) & 0xf;
          sb.append(Integer.toHexString(upper).toUpperCase(Locale.US));

          int lower = ((int) b) & 0xf;
          sb.append(Integer.toHexString(lower).toUpperCase(Locale.US));
        }
      }
    }

    return sb.toString();
  }
  catch (UnsupportedEncodingException uee)
  {
    throw new RuntimeException("UTF-8 unsupported!?", uee);
  }
}

さあ、これを行うライブラリが必要です。
しんぞう

9

URLEncodingは、残念ながら発見したように、HTTP URLを適切にエンコードできます。渡した文字列「http://search.barnesandnoble.com/booksearch/first book.pdf」は、URLエンコードされた形式に正しく完全にエンコードされています。URLのパラメーターとして取得したgobbledigookの長い文字列全体を渡すことができ、渡された文字列に正確にデコードして戻すことができます。

URL全体をパラメータとして渡すのとは少し違うことをしたいようです。私が収集したものから、「http://search.barnesandnoble.com/booksearch/whateverTheUserPassesIn」のような検索URLを作成しようとしています。エンコードする必要があるのは「whateverTheUserPassesIn」ビットだけなので、おそらく次のようにするだけです。

String url = "http://search.barnesandnoble.com/booksearch/" + 
       URLEncoder.encode(userInput,"UTF-8");

それはあなたにとってより有効なものを生み出すはずです。


17
これにより、userInputのスペースが「+」に置き換えられます。ポスターでは、「%20」に置き換える必要があります。
vocaro

@vocaro:それは非常に良い点です。引数のようなURLEncoderエスケープはクエリパラメータであり、URLの他の部分とは異なります。
Brandon Yarbrough、2014

9

プロジェクトに依存関係を追加したくない場合は、これらの関数が役立ちます。

URLの「パス」の部分をここに渡します。おそらく、完全なURLをパラメーターとして渡したくないでしょう(照会ストリングには異なるエスケープが必要など)。

/**
 * Percent-encodes a string so it's suitable for use in a URL Path (not a query string / form encode, which uses + for spaces, etc)
 */
public static String percentEncode(String encodeMe) {
    if (encodeMe == null) {
        return "";
    }
    String encoded = encodeMe.replace("%", "%25");
    encoded = encoded.replace(" ", "%20");
    encoded = encoded.replace("!", "%21");
    encoded = encoded.replace("#", "%23");
    encoded = encoded.replace("$", "%24");
    encoded = encoded.replace("&", "%26");
    encoded = encoded.replace("'", "%27");
    encoded = encoded.replace("(", "%28");
    encoded = encoded.replace(")", "%29");
    encoded = encoded.replace("*", "%2A");
    encoded = encoded.replace("+", "%2B");
    encoded = encoded.replace(",", "%2C");
    encoded = encoded.replace("/", "%2F");
    encoded = encoded.replace(":", "%3A");
    encoded = encoded.replace(";", "%3B");
    encoded = encoded.replace("=", "%3D");
    encoded = encoded.replace("?", "%3F");
    encoded = encoded.replace("@", "%40");
    encoded = encoded.replace("[", "%5B");
    encoded = encoded.replace("]", "%5D");
    return encoded;
}

/**
 * Percent-decodes a string, such as used in a URL Path (not a query string / form encode, which uses + for spaces, etc)
 */
public static String percentDecode(String encodeMe) {
    if (encodeMe == null) {
        return "";
    }
    String decoded = encodeMe.replace("%21", "!");
    decoded = decoded.replace("%20", " ");
    decoded = decoded.replace("%23", "#");
    decoded = decoded.replace("%24", "$");
    decoded = decoded.replace("%26", "&");
    decoded = decoded.replace("%27", "'");
    decoded = decoded.replace("%28", "(");
    decoded = decoded.replace("%29", ")");
    decoded = decoded.replace("%2A", "*");
    decoded = decoded.replace("%2B", "+");
    decoded = decoded.replace("%2C", ",");
    decoded = decoded.replace("%2F", "/");
    decoded = decoded.replace("%3A", ":");
    decoded = decoded.replace("%3B", ";");
    decoded = decoded.replace("%3D", "=");
    decoded = decoded.replace("%3F", "?");
    decoded = decoded.replace("%40", "@");
    decoded = decoded.replace("%5B", "[");
    decoded = decoded.replace("%5D", "]");
    decoded = decoded.replace("%25", "%");
    return decoded;
}

そしてテスト:

@Test
public void testPercentEncode_Decode() {
    assertEquals("", percentDecode(percentEncode(null)));
    assertEquals("", percentDecode(percentEncode("")));

    assertEquals("!", percentDecode(percentEncode("!")));
    assertEquals("#", percentDecode(percentEncode("#")));
    assertEquals("$", percentDecode(percentEncode("$")));
    assertEquals("@", percentDecode(percentEncode("@")));
    assertEquals("&", percentDecode(percentEncode("&")));
    assertEquals("'", percentDecode(percentEncode("'")));
    assertEquals("(", percentDecode(percentEncode("(")));
    assertEquals(")", percentDecode(percentEncode(")")));
    assertEquals("*", percentDecode(percentEncode("*")));
    assertEquals("+", percentDecode(percentEncode("+")));
    assertEquals(",", percentDecode(percentEncode(",")));
    assertEquals("/", percentDecode(percentEncode("/")));
    assertEquals(":", percentDecode(percentEncode(":")));
    assertEquals(";", percentDecode(percentEncode(";")));

    assertEquals("=", percentDecode(percentEncode("=")));
    assertEquals("?", percentDecode(percentEncode("?")));
    assertEquals("@", percentDecode(percentEncode("@")));
    assertEquals("[", percentDecode(percentEncode("[")));
    assertEquals("]", percentDecode(percentEncode("]")));
    assertEquals(" ", percentDecode(percentEncode(" ")));

    // Get a little complex
    assertEquals("[]]", percentDecode(percentEncode("[]]")));
    assertEquals("a=d%*", percentDecode(percentEncode("a=d%*")));
    assertEquals(")  (", percentDecode(percentEncode(")  (")));
    assertEquals("%21%20%2A%20%27%20%28%20%25%20%29%20%3B%20%3A%20%40%20%26%20%3D%20%2B%20%24%20%2C%20%2F%20%3F%20%23%20%5B%20%5D%20%25",
                    percentEncode("! * ' ( % ) ; : @ & = + $ , / ? # [ ] %"));
    assertEquals("! * ' ( % ) ; : @ & = + $ , / ? # [ ] %", percentDecode(
                    "%21%20%2A%20%27%20%28%20%25%20%29%20%3B%20%3A%20%40%20%26%20%3D%20%2B%20%24%20%2C%20%2F%20%3F%20%23%20%5B%20%5D%20%25"));

    assertEquals("%23456", percentDecode(percentEncode("%23456")));

}

これをありがとう、しかし私がスペースをエンコードするために私がしなければならないことは何ですか->あなたの例に従って代わりに%20を使いますか?
N00b Pr0grammer 2017

スペースを%20として説明するように更新
Cuga

7

エンコードされた "/"(%2F)がURLに含まれている場合でも問題があります。

RFC 3986-セクション2.2は、次のように述べています。(RFC 3986-セクション2.2)

しかし、Tomcatには問題があります。

http://tomcat.apache.org/security-6.html-Apache Tomcat 6.0.10で修正済み

重要:ディレクトリトラバーサルCVE-2007-0450

Tomcatは '\'、 '%2F'および '%5C' [...]を許可します。

次のJavaシステムプロパティがTomcatに追加され、URLのパス区切り文字の処理をさらに制御できるようになりました(両方のオプションのデフォルトはfalseです)。

  • org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH:true | false
  • org.apache.catalina.connector.CoyoteAdapter.ALLOW_BACKSLASH:true | false

すべてのURLがプロキシサーバー内にある場合と同じようにTomcatによって処理されることを保証できないため、コンテキストアクセスを制限するプロキシが使用されていないかのように、Tomcatを常に保護する必要があります。

影響:6.0.0-6.0.9

したがって、%2F文字を含むURLを取得した場合、Tomcatは「400 Invalid URI:noSlash」を返します。

Tomcat起動スクリプトでバグ修正を切り替えることができます。

set JAVA_OPTS=%JAVA_OPTS% %LOGGING_CONFIG%   -Dorg.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true 

7

以前の回答のソリューションを使用して何かが適切に機能しなかったため、以前の回答を読んで独自の方法を記述しましたが、それは私にとっては良さそうですが、これで機能しないURLを見つけた場合はお知らせください。

public static URL convertToURLEscapingIllegalCharacters(String toEscape) throws MalformedURLException, URISyntaxException {
            URL url = new URL(toEscape);
            URI uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef());
            //if a % is included in the toEscape string, it will be re-encoded to %25 and we don't want re-encoding, just encoding
            return new URL(uri.toString().replace("%25", "%"));
}

4

私はマットに同意します。実際、チュートリアルで十分に説明されたことはありませんが、URLパスをエンコードする方法と、URLに追加されるパラメーター(クエリ部分、 "? "記号)。それらは同様のエンコーディングを使用しますが、同じではありません。

特に空白文字のエンコード用。URLパスでは%20としてエンコードする必要がありますが、クエリ部分では%20と「+」記号も使用できます。最良のアイデアは、Webブラウザを使用して、Webサーバーに対して自分でテストすることです。

どちらの場合も、I ALWAYSはエンコードしまうコンポーネントごと、決して文字列全体を。実際、URLEncoderはクエリ部分でそれを可能にします。パス部分にはクラスURIを使用できますが、この場合は単一のコンポーネントではなく文字列全体を要求します。

とにかく、私はこれらの問題を回避するための最良の方法は、個人の矛盾しないデザインを使用することだと思いますどうやって?たとえば、aZ、AZ、0-9および_以外の文字を使用してディレクトリやパラメータに名前を付けることはありません。この方法では、すべてのパラメーターの値をエンコードする必要があります。これは、ユーザー入力からのものであり、使用される文字が不明であるためです。


2
問題のURLを使用して、サンプルコード、あなたの答えに入れて良いことだろう
マーティン・セラーノ


3

GUAVAパスエスケープを使用することもできます。 UrlEscapers.urlFragmentEscaper().escape(relativePath)


2

Carlos Heubergerの返信に加えて、デフォルト(80)とは異なるものが必要な場合は、7 paramコンストラクターを使用する必要があります。

URI uri = new URI(
        "http",
        null, // this is for userInfo
        "www.google.com",
        8080, // port number as int
        "/ig/api",
        "weather=São Paulo",
        null);
String request = uri.toASCIIString();

2

上記の内容を少し変更しました。私は最初にポジティブロジックが好きで、HashSetは文字列の検索など、他のいくつかのオプションよりも優れたパフォーマンスを提供する可能性があると思いました。オートボクシングのペナルティがそれだけの価値があるかどうかはわかりませんが、コンパイラーがASCII文字を最適化すれば、ボクシングのコストは低くなります。

/***
 * Replaces any character not specifically unreserved to an equivalent 
 * percent sequence.
 * @param s
 * @return
 */
public static String encodeURIcomponent(String s)
{
    StringBuilder o = new StringBuilder();
    for (char ch : s.toCharArray()) {
        if (isSafe(ch)) {
            o.append(ch);
        }
        else {
            o.append('%');
            o.append(toHex(ch / 16));
            o.append(toHex(ch % 16));
        }
    }
    return o.toString();
}

private static char toHex(int ch)
{
    return (char)(ch < 10 ? '0' + ch : 'A' + ch - 10);
}

// https://tools.ietf.org/html/rfc3986#section-2.3
public static final HashSet<Character> UnreservedChars = new HashSet<Character>(Arrays.asList(
        'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
        'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
        '0','1','2','3','4','5','6','7','8','9',
        '-','_','.','~'));
public static boolean isSafe(char ch)
{
    return UnreservedChars.contains(ch);
}

1

次の標準Javaソリューションを使用します(Webプラットフォームテストによって提供されるテストケースの約100に合格します)。

0. URLが既にエンコードされているかどうかをテストします

1. URLを構造部分に分割します。それに使用java.net.URL します。

2. 各構造パーツを適切にエンコードします!

3.ホスト名IDN.toASCII(putDomainNameHere)Punycodeエンコードするために使用します!

4.java.net.URI.toASCIIString()パーセントエンコード、NFCエンコードunicodeに使用します(NFKCの方が適しています)。

詳細はこちら:https : //stackoverflow.com/a/49796882/1485527


0

HTTP URLの構築に役立つ新しいプロジェクトを作成しました。ライブラリは、パスセグメントとクエリパラメータを自動的にURLエンコードします。

ソースを表示し、https://github.com/Widen/urlbuilderでバイナリをダウンロードできます。

この質問のサンプルURL:

new UrlBuilder("search.barnesandnoble.com", "booksearch/first book.pdf").toString()

作り出す

http://search.barnesandnoble.com/booksearch/first%20book.pdf


0

私も同じ問題を抱えていました。これを解くことによってこれを解決しました:

android.net.Uri.encode(urlString, ":/");

文字列をエンコードしますが、「:」と「/」はスキップします。


0

私はこれを使います

org.apache.commons.text.StringEscapeUtils.escapeHtml4("my text % & < >");

この依存症を追加

 <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-text</artifactId>
        <version>1.8</version>
    </dependency>

-2

私はこの目的を果たすライブラリー、galimatiasを開発しています。Webブラウザーと同じ方法でURLを解析します。つまり、URLがブラウザで機能する場合、galimatiasによって正しく解析されます

この場合:

// Parse
io.mola.galimatias.URL.parse(
    "http://search.barnesandnoble.com/booksearch/first book.pdf"
).toString()

あなたに与えるでしょう:http://search.barnesandnoble.com/booksearch/first%20book.pdf。もちろん、これは最も単純なケースですが、を超えて何でも機能しますjava.net.URI

https://github.com/smola/galimatiasで確認できます。


-3

このような関数を使用できます。完成させて、必要に応じて変更します。

/**
     * Encode URL (except :, /, ?, &, =, ... characters)
     * @param url to encode
     * @param encodingCharset url encoding charset
     * @return encoded URL
     * @throws UnsupportedEncodingException
     */
    public static String encodeUrl (String url, String encodingCharset) throws UnsupportedEncodingException{
            return new URLCodec().encode(url, encodingCharset).replace("%3A", ":").replace("%2F", "/").replace("%3F", "?").replace("%3D", "=").replace("%26", "&");
    }

使用例:

String urlToEncode = ""http://www.growup.com/folder/intérieur-à_vendre?o=4";
Utils.encodeUrl (urlToEncode , "UTF-8")

結果は次のとおりです。http//www.growup.com/folder/int%C3%A9rieur-%C3%A0_vendre?o = 4


1
この答えはURLCodecなしでは不完全です。
ローン侯爵2014

基本的なアドホックユースケースのために、それは理想的ではないのですが、それは十分なの.replaceためupvote()の連鎖
スヴァローグ

-5

文字列url = "" http://search.barnesandnoble.com/booksearch/ ;

これは一定だと思いますが、動的に変更されるのはファイル名のみなので、ファイル名を取得します

文字列ファイル名; //ファイル名を取得します

文字列urlEnc = url + fileName.replace( ""、 "%20");


2
他のすべての違法な文字はどうですか?
ローン侯爵

-7

どうですか:

public String UrlEncode(String in_){

String retVal = "";

try {
    retVal = URLEncoder.encode(in_, "UTF8");
} catch (UnsupportedEncodingException ex) {
    Log.get().exception(Log.Level.Error, "urlEncode ", ex);
}

return retVal;

}


URLEncoderを使用して、ivalid URL文字をエスケープすることはできません。フォームのエンコードのみ。
アーチャー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.