HttpClient и не-ASCII символы URL (á, é, í, ó, ú) - PullRequest
4 голосов
/ 25 августа 2011

Здесь я давно читатель, первый постер.

Я нахожусь в процессе создания бота для испанской вики, которую я администрирую.Я хотел сделать это с нуля, так как одна из моих целей - практиковать Java.Тем не менее, я столкнулся с некоторыми проблемами при попытке сделать запросы GET с HttpClient к URI, которые содержат символы не ASCII, такие как á, é, í, ó или ú.

String url = "http://es.metroid.wikia.com/api.php?action=query&list=categorymembers&cmtitle=Categoría:Mejoras de las Botas"
method = new GetMethod(url);
client.executeMethod(method);

Когда я делаю выше,GetMethod жалуется на URI:

Exception in thread "main" java.lang.IllegalArgumentException: Invalid uri 'http://es.pruebaloca.wikia.com/api.php?action=query&list=categorymembers&cmtitle=Categoría:Mejoras%20de%20las%20Botas&cmlimit=500&format=xml': Invalid query
    at org.apache.commons.httpclient.HttpMethodBase.<init>(HttpMethodBase.java:222)
    at org.apache.commons.httpclient.methods.GetMethod.<init>(GetMethod.java:89)
    at net.metroidover.categorybot.http.HttpRequest.request(HttpRequest.java:69)
    at net.metroidover.categorybot.http.HttpRequest.request(HttpRequest.java:120)
    at net.metroidover.categorybot.http.Action.getCategoryMembers(Action.java:38)
    at net.metroidover.categorybot.bot.BotComponent.<init>(BotComponent.java:58)
    at net.metroidover.categorybot.bot.BotComponent.main(BotComponent.java:80)

Обратите внимание, что в URI, показанном в трассировке стека, пробелы кодируются в %20, а í остаются без изменений.Тот же самый URI отлично работает в браузере, но я не могу обойтись, когда GetMethod его принимает.

Я также попытался сделать следующее:

URI uri = new URI(url, false);
method = new GetMethod(uri.getEscapedURI());
client.executeMethod(method);

Таким образом, URI избежал i s, но двойной пробел избежал пробелов (%2520) ...

http://es.metroid.wikia.com/api.php?action=query&list=categorymembers&cmtitle=Categor%C3%ADa:Mejoras%2520de%2520las%2520Botas&cmlimit=500&format=xml

Теперь, если я не использую пробелы в запросе, двойного экранирования нет иЯ получаю желаемый результат.Так что если бы не было возможности не-ASCII-символов, мне не нужно было бы использовать класс URI, и я бы не получил двойной выход.Пытаясь избежать первого выхода из пробелов, я попытался это сделать:

URI uri = new URI(url, true);
method = new GetMethod(uri.getEscapedURI());
client.executeMethod(method);

Но классу URI это не понравилось:

org.apache.commons.httpclient.URIException: Invalid query
    at org.apache.commons.httpclient.URI.parseUriReference(URI.java:2049)
    at org.apache.commons.httpclient.URI.<init>(URI.java:167)
    at net.metroidover.categorybot.http.HttpRequest.request(HttpRequest.java:66)
    at net.metroidover.categorybot.http.HttpRequest.request(HttpRequest.java:121)
    at net.metroidover.categorybot.http.Action.getCategoryMembers(Action.java:38)
    at net.metroidover.categorybot.bot.BotComponent.<init>(BotComponent.java:58)
    at net.metroidover.categorybot.bot.BotComponent.main(BotComponent.java:80)
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 1, Size: 0
    at java.util.ArrayList.RangeCheck(ArrayList.java:547)
    at java.util.ArrayList.get(ArrayList.java:322)
    at net.metroidover.categorybot.http.Action.getCategoryMembers(Action.java:39)
    at net.metroidover.categorybot.bot.BotComponent.<init>(BotComponent.java:58)
    at net.metroidover.categorybot.bot.BotComponent.main(BotComponent.java:80)

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

Спасибо!

Редактировать: Решение, которое лучше всего подходит для меня, - это решение Парсифаля, но, как дополнение,Я хотел бы сказать, что установка пути с помощью method.setPath(url) сделала HttpMethod отклонением файла cookie, который мне нужно было сохранить:

Aug 26, 2011 4:07:08 PM org.apache.commons.httpclient.HttpMethodBase processCookieHeaders
WARNING: Cookie rejected: "wikicities_session=900beded4191ff880e09944c7c0aaf5a". Illegal path attribute "/". Path of origin: "http://es.metroid.wikia.com/api.php"

Однако, если я отправлю URI конструктору и забуду о setPath(url), файл cookie сохраняется без проблем.

String url = "http://es.metroid.wikia.com/api.php";
NameValuePair[] query = { new NameValuePair("action", "query"), new NameValuePair("list", "categorymembers"),
            new NameValuePair("cmtitle", "Categoría:Mejoras de las Botas"), new NameValuePair("cmlimit", "500"),
            new NameValuePair("format", "xml") };
HttpMethod method = null;

...

method = new GetMethod(url);  // Or PostMethod(url)
method.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY); // It had been like this the whole time
method.setQueryString(query);
client.executeMethod(method);

Ответы [ 3 ]

5 голосов
/ 25 августа 2011

Я бы рекомендовал использовать UrlEncoder для кодирования значений queryString (не всей строки queryString).

UrlEncoder.encode("Categoría:Mejoras de las Botas", "UTF-8");
2 голосов
/ 25 августа 2011

Глядя на документацию HttpMethodBase , выясняется, что все параметры String должны быть предварительно закодированы. Самое простое решение состоит в том, чтобы создать ваш URL поэтапно, с setPath() и вариантом setQueryString(), который принимает массив параметров имя-значение.

0 голосов
/ 25 августа 2011

почему бы вам не попытаться добавить параметры как NameValuePair, проблема здесь в том, что когда вы экранируете URL, все в URL экранируется, включая такие вещи, как http: // .., вот почему система жалуется.

Вы также можете экранировать только аргументы, используя URLEncoder.encode(), просто передайте в него параметры get и добавьте возвращаемое значение в URL.

String url = "http://es.metroid.wikia.com/api.php?"+URLEncoder.encode("action=query&list=categorymembers&cmtitle=Categoría:Mejoras de las Botas");

...