2010-11-19 4 views
5

Ich habe etwas Code für mein Android-Gerät geschrieben, um sich auf einer Website über https einzuloggen und einige Daten aus den resultierenden Seiten zu analysieren. Eine HttpGet passiert zuerst, um einige Informationen für die Anmeldung benötigt, dann eine HttpPost, um den eigentlichen Login-Prozess zu tun.HttpPost funktioniert in Java-Projekt, nicht in Android

Der folgende Code funktioniert gut in einem Java-Projekt innerhalb von Eclipse, die die folgenden Jar-Dateien auf dem Build-Pfad hat: httpcore-4.1-beta2.jar, httpclient-4.1-alpha2.jar, httpmime-4.1-alpha2.jar, commons-logging-1.1.1.jar.

public static MyBean gatherData(String username, String password) { 
    MyBean myBean = new MyBean(); 
    try { 
     HttpResponse response = doHttpGet(URL_PAGE_LOGIN, null, null); 
     System.out.println("Got login page"); 
     String content = EntityUtils.toString(response.getEntity()); 
     String token = ContentParser.getToken(content); 
     String cookie = getCookie(response); 
     System.out.println("Performing login"); 
     System.out.println("token = "+token +" || cookie = "+cookie); 
     response = doLoginPost(username,password,cookie, token); 
     int respCode = response.getStatusLine().getStatusCode(); 
     if (respCode != 302) { 
      System.out.println("ERROR: not a 302 redirect!: code is \""+ respCode+"\""); 
      if (respCode == 200) { 
       System.out.println(getHeaders(response)); 
       System.out.println(EntityUtils.toString(response.getEntity()).substring(0, 500)); 
      } 
     } else { 
      System.out.println("Logged in OK, loading account home"); 
      // redirect handler and rest of parse removed 
     } 
    }catch (Exception e) { 
     System.out.println("ERROR in gatherdata: "+e.toString()); 
     e.printStackTrace(); 
    } 
    return myBean; 
} 
private static HttpResponse doHttpGet(String url, String cookie, String referrer) { 
    try { 
     HttpClient client = new DefaultHttpClient(); 
     client.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1); 
     client.getParams().setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, "UTF-8"); 
     HttpGet httpGet = new HttpGet(url); 
     httpGet.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1); 
     httpGet.setHeader(HEADER_USER_AGENT,HEADER_USER_AGENT_VALUE); 
     if (referrer != null && !referrer.equals("")) httpGet.setHeader(HEADER_REFERER,referrer); 
     if (cookie != null && !cookie.equals("")) httpGet.setHeader(HEADER_COOKIE,cookie); 
     return client.execute(httpGet); 
    } catch (Exception e) { 
     e.printStackTrace(); 
     throw new ConnectException("Failed to read content from response"); 
    } 
} 
private static HttpResponse doLoginPost(String username, String password, String cookie, String token) throws ClientProtocolException, IOException { 
    try { 
     HttpClient client = new DefaultHttpClient(); 
     client.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1); 
     client.getParams().setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, "UTF-8"); 
     HttpPost post = new HttpPost(URL_LOGIN_SUBMIT); 
     post.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1); 
     post.setHeader(HEADER_USER_AGENT,HEADER_USER_AGENT_VALUE); 
     post.setHeader(HEADER_REFERER, URL_PAGE_LOGIN); 
     post.setHeader(HEADER_COOKIE, cookie); 
     post.setHeader("Content-Type","application/x-www-form-urlencoded"); 
     List<NameValuePair> formParams = new ArrayList<NameValuePair>(); 
     formParams.add(new BasicNameValuePair("org.apache.struts.taglib.html.TOKEN", token)); 
     formParams.add(new BasicNameValuePair("showLogin", "true")); 
     formParams.add(new BasicNameValuePair("upgrade", "")); 
     formParams.add(new BasicNameValuePair("username", username)); 
     formParams.add(new BasicNameValuePair("password", password)); 
     formParams.add(new BasicNameValuePair("submit", "Secure+Log+in")); 
     UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formParams,HTTP.UTF_8); 
     post.setEntity(entity); 
     return client.execute(post); 
    } catch (Exception e) { 
     e.printStackTrace(); 
     throw new ConnectException("ERROR in doLoginPost(): "+e.getMessage()); 
    } 
} 

Der Server (die nicht unter meiner Kontrolle ist) gibt eine 302-Umleitung, wenn die Anmeldung erfolgreich war, und 200, wenn es fehlschlägt und wieder lädt die Login-Seite. Wenn ich mit den obigen Jar-Dateien laufe, bekomme ich die 302-Umleitung, aber wenn ich den exakt gleichen Code von einem Android-Projekt mit der Android-Jar-Datei 1.6 auf dem Build-Pfad laufe, bekomme ich die 200 Antwort vom Server. Ich bekomme die gleiche 200 Antwort, wenn ich den Code auf meinem 2.2 Gerät ausführe.

Meine Android-Anwendung hat Internet-Berechtigungen, und die HttpGet funktioniert gut. Ich gehe davon aus, dass das Problem in der Tatsache liegt, dass sich HttpPost (oder eine andere Klasse) in einer signifikanten Weise zwischen der Android Jar-Version und den neueren Apache-Versionen unterscheidet.

Ich habe versucht, die Apache-Bibliotheken zum Build-Pfad des Android-Projekts hinzufügen, aber aufgrund der doppelten Klassen bekomme ich Nachrichten wie: INFO/dalvikvm(390): DexOpt: not resolving ambiguous class 'Lorg/apache/http/impl/client/DefaultHttpClient;' im Protokoll. Ich habe auch versucht, eine MultipartEntity anstelle der UrlEncodedFormEntity zu verwenden, aber ich bekomme das gleiche Ergebnis 200.

Also, ich habe ein paar Fragen:
- Kann ich den Code zwingen, unter Android die neueren Apache-Bibliotheken anstelle der Android-Versionen zu verwenden?
- Wenn nicht, hat jemand irgendwelche Ideen, wie kann ich meinen Code ändern, so dass es mit dem Android Jar funktioniert?
- Gibt es andere, völlig andere Ansätze, um eine HttpPost in Android zu tun?
- Irgendwelche anderen Ideen?

Ich habe readalotofposts und code aber ich bin nicht weiter. Ich bin seit ein paar Tagen dran und weiß nicht, wie ich das Ding zur Arbeit bringen soll, also werde ich an dieser Stelle alles versuchen. Danke im Voraus.

Antwort

6

gehen habe ich jetzt darauf, die HttpClient Route der erwartete Antwort zu geben aufgegeben vom Server, wenn auf Android ausgeführt. Stattdessen habe ich die obige Methode doPost umgeschrieben, um stattdessen eine HttpsURLConnection zu verwenden. Hier ist die neue (funktionierende) Version in der Hoffnung, dass sie für jemanden nützlich ist.

private static LoginBean altPost(String username, String password, String cookie, String token){ 
    LoginBean loginBean = new LoginBean(); 
    HttpsURLConnection urlc = null; 
    OutputStreamWriter out = null; 
    DataOutputStream dataout = null; 
    BufferedReader in = null; 
    try { 
     URL url = new URL(URL_LOGIN_SUBMIT); 
     urlc = (HttpsURLConnection) url.openConnection(); 
     urlc.setRequestMethod("POST"); 
     urlc.setDoOutput(true); 
     urlc.setDoInput(true); 
     urlc.setUseCaches(false); 
     urlc.setAllowUserInteraction(false); 
     urlc.setRequestProperty(HEADER_USER_AGENT, HEADER_USER_AGENT_VALUE_FF); 
     urlc.setRequestProperty("Cookie", cookie); 
     urlc.setRequestProperty("Content-Type","application/x-www-form-urlencoded"); 
     String output = "org.apache.struts.taglib.html.TOKEN="+ URLEncoder.encode(token, HTTP.UTF_8) 
       +"&showLogin=true&upgrade=&username="+ URLEncoder.encode(username, HTTP.UTF_8) 
       +"&password="+ URLEncoder.encode(password, HTTP.UTF_8)+"&submit=" 
       +URLEncoder.encode("Secure+Log+in", HTTP.UTF_8); 
     dataout = new DataOutputStream(urlc.getOutputStream()); 
     // perform POST operation 
     dataout.writeBytes(output); 
     // get response info 
     loginBean.setResponseCode(urlc.getResponseCode()); 
     // get required headers 
     String headerName = null; 
     StringBuffer newCookie = new StringBuffer(100); 
     String redirectLocation = ""; 
     for (int i=1; (headerName = urlc.getHeaderField(i)) != null;i++) { 
      if (headerName.indexOf(COOKIE_VALUE_SESSION) > -1) { 
       if (newCookie.length() > 0) {newCookie.append("; ");} 
       newCookie.append(headerName); 
      } 
      if (headerName.indexOf(COOKIE_VALUE_AUTH) > -1) { 
       if (newCookie.length() > 0) {newCookie.append("; ");} 
       newCookie.append(headerName); 
      } 
      if (headerName.indexOf("https://") > -1) { 
       redirectLocation = headerName; 
      } 
     } 
     loginBean.setCookie(newCookie.toString()); 
     loginBean.setRedirectUrl(redirectLocation); 

     in = new BufferedReader(new InputStreamReader(urlc.getInputStream()),8096); 
     String response; 
     // write html to System.out for debug 
     while ((response = in.readLine()) != null) { 
      System.out.println(response); 
     } 
     in.close(); 
    } catch (ProtocolException e) { 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } finally { 
     if (out != null) { 
      try { 
       out.close(); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     } 
     if (in != null) { 
      try { 
       in.close(); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 
    return loginBean; 
} 

Ich habe immer noch keine Ahnung, warum die HttpClient Art und Weise nicht richtig funktioniert.

+1

gute Antwort. in Lebkuchen und später, HttpURLConnection ist der Weg zu gehen. Betrachte Apache HttpClient als veraltet. –

0

Ist es möglich, dass diese Website User-Agent-Erkennung durchführt und tatsächlich andere Ergebnisse zurückgibt, weil es Android ist? Wenn man bedenkt, dass 200 Erfolg bedeutet, warum muss es dann eine 302 anstelle einer 200 geben? Haben Sie das Ergebnis, das Sie erhalten, wenn es eine 200 zurückgibt, ausgedruckt und gibt es zusätzliche Informationen?

+0

Das 200 Ergebnis ist nur die Benutzer-Login-Seite wieder sehr nützlich sein würde, zu vermeiden, mit keine Fehlermeldungen oder andere Informationen, was normalerweise bei einem falschen Login passiert. Ich setze den Benutzer-Agenten explizit in den Headern, und es wird auf die gleiche Weise wie der Code aufgerufen wird festgelegt. Ich kann mich auf der Website OK von dem Browser auf meinem Android-Handy anmelden, was bedeutet, dass es nicht auf der Grundlage seiner Android-Blockierung blockiert. –

0

die RedirectHandler prüfen, überschreibt den Standard ein und es einige Protokollierung tun, hatte ich damit Probleme bei Android ...

+0

Ich bin ziemlich zufrieden mit dem Redirect-Code (den ich oben nicht erwähnt habe), das Problem ist, dass ich nicht so weit komme. Da der Server einen 200-Code von Android zurückgibt und nicht den 302, der von Eclipse zurückgegeben wird, komme ich nicht zu dem Teil, wo ich die Umleitung handhaben muss. –

+0

Hm, könnte es ein User-Agent-Problem sein? – dacwe

+0

Der Benutzeragent wird im obigen Code festgelegt und auf denselben Wert gesetzt, unabhängig davon, ob er innerhalb von Android oder als reines Java ausgeführt wird. Ich habe versucht, ein Android-Benutzer-Agent, ein FF/Windows ein und einige benutzerdefinierte. Sie alle geben das gleiche Verhalten an. –

1

die Kollisionen verwenden dieses Glas für Httpclient

httplib

und dieser Beitrag auch

stack overflow post

+0

würde für jemanden für zukünftige Verwendung helfen ... –

Verwandte Themen