2011-08-25 4 views
4

'장시간 독자, 처음 포스터'는 여기에 있습니다.HttpClient 및 비 ASCII URL 문자 (á, é, í, ó, ú)

내가 관리하는 스페인어 위키에 대해 bot을 만드는 중입니다. 저는 처음부터 그것을 만들고 싶었습니다. 저의 목적 중 하나는 자바를 연습하는 것이 었습니다. 그러나 HttpClient를 사용하여 GET 요청을 á, é, í, ó 또는 ú와 같은 비 ASCII 문자가 포함 된 URI로 만들려고 할 때 문제가 발생했습니다. 스택 트레이스에 도시 된 URI에 공간 %20로 부호화되었는지

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) 

참고하고 그대로 í들 남아 :

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

I 위 이렇게하면 getMethod 메소드는 URI 뿌려 . 정확히 똑같은 URI가 브라우저에서 완벽하게 작동하지만 GetMethod를 받아 들일 수는 없습니다. URIi의 탈출,

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

이 방법하지만, 이중 경우, 지금 공간 (%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 내가 저장하기 위해 필요한 쿠키를 거부했다 말을하고 싶습니다
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)을 잊어 버리면 쿠키가 문제없이 저장됩니다.

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

답변

2

HttpMethodBase의 문서를 보면, 모든 String 매개 변수를 미리 인코딩해야 할 것으로 보인다. 가장 간단한 해결 방법은 URL을 생성하는 단계이며 setPath()setQueryString() 변형은 이름 - 값 매개 변수 배열을 사용합니다.

+0

야이! 그건 완벽하게 작동합니다. 사실 이미 매개 변수를'ArrayList '로 보내고 있었기 때문에 많은 코드를 변경할 필요가 없었습니다. 감사합니다 :) – ianmartorell

5

UrlEncoder을 사용하여 queryString 값 (전체 queryString이 아님)을 인코딩하는 것이 좋습니다.당신이 NameValuePair로 PARAMS을 추가하지 않는 이유

UrlEncoder.encode("Categoría:Mejoras de las Botas", "UTF-8"); 
+0

꽤 잘 작동하지만 모든 쿼리 매개 변수를 별도로 인코딩해야 할 것입니다. parsifal의 대답은 모든'NameValuePair'가'method.setQueryString (pairs);'으로 한 번에 인코딩되고,'pairs'는'NameValuePair []'로 더 유용합니다. – ianmartorell

-1

, 여기에 문제가 당신이 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");

+0

모든 매개 변수는 별도로 인코딩해야한다고 생각합니다. 그렇지 않으면 &와 =가 인코딩됩니다. –

+0

그래, @JB Nizet처럼, 당신이 별도로 인코딩해야한다 그렇지 않으면 당신은'http://es.metroid.wikia.com/api.php?action%3Dquery%26list%3Dcategorymembers%26c mtitle % 3DCategor % C3 % ADa % 3AMejoras + de + las + Botas'. – ianmartorell