HTTP URL-адрес кодирования в Java

366

Мое автономное приложение на Java получает от пользователя URL-адрес (который указывает на файл), и мне нужно нажать его и загрузить. Проблема в том, что я не могу правильно закодировать URL-адрес HTTP ...

Пример:

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)

Я предполагаю, URLEncoderчто не предназначен для кодирования URL-адресов HTTP ... JavaDoc говорит "Класс служебных программ для кодирования форм HTML" ... Есть ли другой способ сделать это?

suDocker
источник
1
Смотрите также stackoverflow.com/questions/10786042/...
Raedwald
Поведение совершенно правильно. URL-кодирование - это преобразование чего-либо в строку, которую можно безопасно передать в качестве параметра URL-адреса и совсем не интерпретировать как URL-адрес. Принимая во внимание, что вы хотите просто конвертировать одну небольшую часть URL.
Стивен Холт

Ответы:

303

Класс java.net.URI может помочь; в документации по URL вы найдете

Обратите внимание, что при определенных обстоятельствах класс URI выполняет экранирование своих компонентных полей. Рекомендуемый способ управления кодированием и декодированием URL-адресов - использовать URI.

Используйте один из конструкторов с более чем одним аргументом, например:

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

(конструктор URI с одним аргументом НЕ экранирует недопустимые символы)


Только недопустимые символы экранируются вышеуказанным кодом - он НЕ экранирует символы, не входящие в ASCII (см. Комментарий Фатиха). Метод может быть использован , чтобы получить строку только с US-ASCII символов:
toASCIIString

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();
user85421
источник
13
Обратите внимание, что упомянутый здесь класс URI взят из «org.apache.commons.httpclient.URI», а не «java.net», «java.net» не принимает URI и не принимает недопустимые символы, если только вы не используете конструкторы, которые создают URL из его компонентов, как описано в комментарии Мэтта ниже
Мохамед Фарамави,
7
@Mohamed: класс, который я упоминал и использовал для тестирования, на самом деле java.net.URI : он работал отлично (Java 1.6). Я бы упомянул полное имя класса, если бы оно не было стандартным Java, и ссылка указывает на документацию java.net.URI. И, судя по комментарию Судхакара, он решил проблему, не включив никаких «общих библиотек»!
user85421
1
URI uri = новый URI ("http", "search.barnesandnoble.com", "/ booksearch / é", null); Не правильно ли сбежать с этим образцом? Этого следовало избежать с помощью% escapes
fmucar
@fatih - это правильно, спасибо! Обычно это не должно быть проблемой, но есть простое решение - почти такое же, как я писал ранее. Смотрите 2-е редактирование.
user85421
@Carlos Thx для редактирования. Теперь он убегает, но не правильно убегает. Следует добавить% к HEX-значению char для параметров Path, означающих, что é char следует преобразовать в% e9
fmucar
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.

Следующие два примера подчеркивают различия между ними.

Следующее дает неправильные параметры, в соответствии со стандартом 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
Matt
источник
2
Правильно, конструктор URI уже кодирует строку запроса в соответствии с документацией docs.oracle.com/javase/1.4.2/docs/api/java/net/… , java.lang.String, java.lang.String, int , java.lang.String, java.lang.String, java.lang.String)
Мэдок
8
@Draemon Ответ верен, но использует строку запроса необычным образом; более нормальный пример может быть query = URLEncoder.encode(key) + "=" + URLEncoder.encode(value). В документах просто говорится, что «любой символ, который не является допустимым символом URI, указан в кавычках».
тк.
1
Я согласен с Мэттом здесь. Если вы введете этот URL-адрес: « google.com/help/me/book name + me /? MY CRZY QUERY! + & + :)» в браузере, он автоматически кодирует пробелы, но «&» используется в качестве значения запроса разделитель и "+" потеряны.
arcot
80

Я собираюсь добавить одно предложение, предназначенное для пользователей Android. Вы можете сделать это, чтобы избежать необходимости получать какие-либо внешние библиотеки. Кроме того, все решения поиска / замены символов, предложенные в некоторых из приведенных выше ответов, опасны и их следует избегать.

Попробуйте это:

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
2
Это не может справиться #.
Олстон
Или, если вы просто хотите использовать кавычки пути: новый URI (
ноль, ноль
1
@Stallman Если имя вашего файла содержит #, класс URL поместит его в «ref» (эквивалент «фрагмента» в классе URI). Вы можете определить, возвращает ли URL.getRef () что-то, что может рассматриваться как часть пути, и передать URL.getPath () + "#" + URL.getRef () в качестве параметра "path", а null - в качестве "фрагмента". msgstr "параметр конструктора параметров 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;
    }

}
fmucar
источник
3
это также требует, чтобы вы разбили URL на части. Компьютер не может знать, какую часть URL кодировать. Смотрите мой выше edit
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», чего и пытался избежать первоначальный вопрос.
Бенджамин Пиетт
2
Вы передаете только то, что вам нужно для кодирования, а не весь URL. Невозможно передать одну целую строку URL и ожидать правильной кодировки. Во всех случаях вам нужно разбить URL на его логические части.
fmucar
2
У меня были проблемы с этим ответом, потому что он не кодирует небезопасные символы в UTF-8 .. может зависеть от приложения-партнера.
Тарншаф
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
URLDecoder.decode (строка, «UTF-8») завершается с ошибкой IllegalArgumentException при передаче строки как « google.co.in/search?q=123%!123 ». Это действительный URL. Я думаю, этот API не работает, когда% используется в качестве данных вместо символа кодирования.
MediumOne
26

Да, URL-кодирование будет кодировать эту строку, чтобы она правильно передавалась по URL-адресу в конечный пункт назначения. Например, у вас не может быть http://stackoverflow.com?url=http://yyy.com . UrlEncoding параметра будет фиксировать значение этого параметра.

Итак, у меня есть два варианта для вас:

  1. У вас есть доступ к пути отдельно от домена? Если это так, вы можете просто UrlEncode пути. Однако, если это не так, то вариант 2 может быть для вас.

  2. Получите commons-httpclient-3.1. Это имеет класс URIUtil:

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

Это выведет именно то, что вы ищете, поскольку закодирует только часть пути URI.

К вашему сведению, для работы этого метода во время выполнения вам понадобятся кодексы и регистрация.

Натан Фегер
источник
Sidenote apache commons прекратил поддерживать URIUtil в ветвях 4.x, по-видимому, рекомендовав вместо этого использовать класс URI JDK. Просто означает, что вы должны разбить нить самостоятельно.
Николи
2) Точно также здесь предлагается stackoverflow.com/questions/5330104/… Я также использовал URIUtilрешение
К
11

Пометка: строка, содержащая символ пробела по определению, не является URI. Итак, вы ищете код, который реализует экранирование URI, определенное в Разделе 2.1 RFC 3986 .

Джулиан Решке
источник
Нам нужно «как» в ответах, а не «что».
Синдзоу
11

К сожалению, org.apache.commons.httpclient.util.URIUtilэто устарело, и replacement org.apache.commons.codec.net.URLCodecделает кодирование подходящим для сообщений в форме, а не в реальных URL. Поэтому мне пришлось написать свою собственную функцию, которая выполняет один компонент (не подходит для целых строк запроса, которые имеют? S и & s)

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-кода. Вы можете передать всю длинную строку gobbledigook, которую вы вернули, в качестве параметра в URL, и она может быть декодирована обратно в ту строку, в которой вы были переданы.

Похоже, вы хотите сделать что-то немного отличное от передачи всего URL-адреса в качестве параметра. Из того, что я понял, вы пытаетесь создать поисковый URL, который выглядит как " http://search.barnesandnoble.com/booksearch/whwhatTheUserPassesIn ". Единственное, что вам нужно кодировать, это бит "whatTheUserPassesIn", так что, возможно, все, что вам нужно сделать, это что-то вроде этого:

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

Это должно произвести что-то более правильное для вас.

Брэндон Ярбро
источник
17
Это заменит пробелы в userInput на «+». Плакат нуждается в их замене на "% 20".
Вокаро
@ Vocaro: это очень хороший момент. URLEncoder экранирует, как аргументы являются параметрами запроса, а не как остальная часть URL.
Брэндон Ярбро
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")));

}
Cuga
источник
Спасибо за это, но что мне нужно сделать, чтобы закодировать пробел -> вместо этого использовать% 20 ​​в соответствии с вашим примером?
N00b Pr0grammer
Обновлено для учета пробелов как% 20
Cuga
7

Проблема все еще существует, если в вашем URL есть закодированный символ "/" (% 2F).

RFC 3986 - раздел 2.2 гласит: «Если данные для компонента URI будут конфликтовать с целью использования зарезервированного символа в качестве разделителя, то конфликтующие данные должны быть закодированы в процентах до формирования URI». (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

Из-за невозможности гарантировать, что Tomcat обрабатывает все URL-адреса, как они находятся на прокси-серверах, Tomcat всегда должен быть защищен, как если бы прокси-сервер не ограничивал доступ к контексту.

Влияет: 6.0.0-6.0.9

Поэтому, если у вас есть URL с символом% 2F, Tomcat возвращает: «400 Invalid URI: noSlash»

Вы можете переключить исправление в скрипте запуска Tomcat:

set JAVA_OPTS=%JAVA_OPTS% %LOGGING_CONFIG%   -Dorg.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true 
simonox
источник
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, а также знак «+». Лучшая идея - протестировать ее самостоятельно на нашем веб-сервере с помощью веб-браузера.

В обоих случаях я ВСЕГДА закодировал бы КОМПОНЕНТ ПО КОМПОНЕНТУ , а не всю строку. Действительно, URLEncoder допускает это для части запроса. Для части пути вы можете использовать класс URI, хотя в этом случае он запрашивает всю строку, а не один компонент.

В любом случае, я считаю, что лучший способ избежать этих проблем - использовать личный неконфликтный дизайн. Как? Например, я никогда не назову каталоги или параметры, используя символы, отличные от aZ, AZ, 0-9 и _. Таким образом, единственной необходимостью является кодирование значения каждого параметра, поскольку оно может быть получено из пользовательского ввода, а используемые символы неизвестны.

negora
источник
2
Пример кода с использованием URL-адреса в вопросе было бы полезно добавить в ваш ответ
Мартин Серрано,
3

Может быть, можете попробовать UriUtils в org.springframework.web.util

UriUtils.encodeUri(input, "UTF-8")
micahli123
источник
3

Вы также можете использовать GUAVAи путь escape: UrlEscapers.urlFragmentEscaper().escape(relativePath)

К кра
источник
2

В дополнение к ответу Карлоса Хойбергера: если требуется значение, отличное от значения по умолчанию (80), следует использовать конструктор 7 параметров:

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);
}
ChrisG65
источник
1

Используйте следующее стандартное решение Java (проходит около 100 тестовых случаев, предоставляемых Web Plattform Tests ):

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

jschnasse
источник
0

Я создал новый проект, чтобы помочь создать URL-адреса HTTP. Библиотека автоматически 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

У меня такая же проблема. Решил это с помощью unsing:

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>
разработчик learn999
источник
-2

Я разрабатываю библиотеку, которая служит этой цели: galimatias . Он анализирует 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

Smola
источник
-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.
маркиз Лорн
upvote для цепочки .replace (), это не идеально, но этого достаточно для базовых специальных случаев использования
svarog
-5

String url = "" http://search.barnesandnoble.com/booksearch/ ;

Я думаю, это будет константа, и только имя файла будет изменено динамически, поэтому получите имя файла

Строка имени файла; // получить имя файла

String 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;

}

MichaelICE
источник
URLEncoder нельзя использовать для экранирования недействительных символов URL. Только для кодирования форм.
Арчер