«Давний читатель, первый плакат» здесь.
Я занимаюсь созданием бота для испанской Wiki, которую я администрирую. Я хотел сделать его с нуля, так как одна из целей моего создания - практиковать 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
, но удваивал экранирование пробелов (%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 ответа
Изучите документацию HttpMethodBase , похоже, все параметры String
должны быть предварительно закодированы. Самым простым решением является построение URL-адреса поэтапно с использованием setPath()
и варианта setQueryString()
, который принимает массив параметров значения имени.
Я бы рекомендовал использовать UrlEncoder
для кодирования значений вашей строки запроса (а не всей строки запроса).
UrlEncoder.encode("Categoría:Mejoras de las Botas", "UTF-8");
Почему бы вам не попробовать добавить параметры как NameValuePair
, проблема здесь в том, что, когда вы экранируете URL, все в URL экранируются, включая такие вещи, как http: // .. вот почему система жалуется.
Вы также можете избежать только аргументов, используя URLEncoder.encode()
, просто передайте ему параметры получения и добавьте возвращаемое значение к URL-адресу.
String url = "http://es.metroid.wikia.com/api.php?"+URLEncoder.encode("action=query&list=categorymembers&cmtitle=Categoría:Mejoras de las Botas");
Похожие вопросы
Новые вопросы
java
Java - это язык программирования высокого уровня. Используйте этот тег, если у вас возникли проблемы с использованием или пониманием самого языка. Этот тег редко используется отдельно и чаще всего используется вместе с [spring], [spring-boot], [jakarta-ee], [android], [javafx], [hadoop], [gradle] и [maven].