Правильное кодирование символов в URL при использовании HttpClient - PullRequest
5 голосов
/ 23 июня 2011

У меня есть список URL-адресов, которые необходимо проверить, являются ли они действительными. Я написал программу на Java, которая использует Apache HttpClient для проверки ссылки. Мне пришлось реализовать собственную стратегию перенаправления из-за присутствия недопустимых символов (например, {} в URL-адресах перенаправления), о которых по умолчанию не говорилось. Работает нормально в большинстве случаев, кроме 2 из них:

  1. Экранированные символы в пути или параметрах запроса, которые не следует кодировать дальше. Пример:

    String url = "http://www.example.com/chapter1/%3Fref%3Dsomething%26term%3D?ref=xyz"
    

    Если я использую объект URI, он заглушает символ "{".

    URI myUri = new URI(url) ==> This will fail. 
    

    Если я бегу:

    URI myUri = new URI(UriUtils.encodeHttpUrl(url)) 
    

    кодирует% 3F в% 253F. Однако, когда я перехожу по ссылке, используя Chrome или Fiddler, я не вижу, что% 3F снова экранируется. Как мне защитить от чрезмерного кодирования пути или параметров запроса?

  2. Последний параметр запроса в URL-адресе также имеет действительный URL-адрес. Например.

    String url = "www.example.com/Chapter1/?param1=xyz&param2=http://www.google.com/?abc=1"
    

Моя текущая стратегия кодирования разделяет параметры запроса, а затем вызывает URLEncoder.encode для параметров запроса. Это, однако, приводит к тому, что последний параметр также кодируется (что не так, когда я следую за ним в Fiddler или Chrome).

Я пробовал несколько вещей (используя UriUtils, особые случаи для URL-адресов в качестве последнего параметра и другие хаки), но ничто не кажется идеальным. Какой лучший способ решить эту проблему?

Ответы [ 4 ]

3 голосов
/ 23 июня 2011

Как защитить от избыточного кодирования пути или параметров запроса?

Вы не можете "защитить от избыточного кодирования". Вы либо кодируете, либо нет. Вы должны всегда знать для любой данной строки, закодирована она или нет. Вы должны кодировать только строки, которые еще не закодированы, и вы никогда не должны кодировать строки, которые уже закодированы.

Так эта строка закодирована или нет?

%3Fref%3Dsomething%26term%3D{keyword}

Мне кажется, что это плохой ввод: очевидно, это не кодированный , потому что он содержит недопустимые символы ('{' и '}'). Тем не менее, она также не является некодированной строкой, поскольку содержит последовательности «% xx». Так что это частично закодировано. Как только строка находится в этой форме, программного решения не существует - вам просто нужно избегать попадания строки в такую ​​форму. Вы можете создать алгоритм, который «исправляет» эту строку, тщательно отыскивая части, похожие на «%», за которыми следуют две шестнадцатеричные цифры, и оставляя их в покое. Но это сломается на тонких случаях. Рассмотрим некодированную строку «42% 23», которая должна быть буквальным представлением математического выражения «42 mod 23». Когда я помещаю это в URI, я ожидаю, что он будет закодирован как «42% 2523», поэтому он будет декодирован как «42% 23», но приведенный выше алгоритм сломается и закодирует его как «42% 23», который затем будет декодирован как « 42 #». Таким образом, нет способа исправить вышеуказанную строку. Кодировка "% 3F" в "% 253F" - это именно то, что должен делать кодировщик URI.

Примечание. Сказав это, браузеры часто позволяют вам вводить плохие символы в URI, и они автоматически их кодируют. Это не очень надежно, поэтому его не следует использовать, если вы не пытаетесь прощать ввод пользователя. В этом случае вы можете сделать «лучшее из возможного», сначала расшифровав URI, а затем перекодировав его. В этом случае, если бы я хотел набрать «42% 23», мне пришлось бы вручную ввести «42% 2523».

Что касается вопроса 2:

Это, однако, приводит к тому, что последний параметр также кодируется

Точно так же, это именно то, что вы хотите. Если URI отображается в качестве параметра внутри другого URI, его значение должно быть в процентах. В противном случае, как вы можете определить, где заканчивается один URI, а другой продолжается? Я полагаю, что приведенный выше URI действительно действителен (поскольку ':', '/', '&' и '=' являются зарезервированными символами, а не запрещены, и поэтому они разрешены, если они не создают неоднозначность). Но гораздо безопаснее избежать использования URI внутри URI.

3 голосов
/ 23 июня 2011

Я действительно не знаю, но вы можете сначала попытаться декодировать его, поэтому %3F вернет то, что было, а затем закодирует его обратно.

Итак:

String decoded = URLDecoder.decode(url, "UTF-8");
url = URLEncoder.encode(decoded, "UTF-8");
1 голос
/ 23 июня 2011

Правильный способ кодирования незашифрованной строки URL-адреса - через URI.toASCIIString ().

Конечно, вы сами решаете, закодирован ли уже URL или нет.

0 голосов
/ 23 июня 2011

Вы пытались использовать URLEncoder?

    URLEncoder.encode(URLString, "UTF-8")

Кроме того, ваша единственная возможность - кодировать каждый URL, который используется в качестве параметра, отдельно, а затем вручную создавать URL.Это довольно сложный случай.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...