2010-11-19 22 views
5

He escrito un código para mi dispositivo Android para iniciar sesión en un sitio web más https y analizar algunos datos de las páginas resultantes. Un HttpGet pasa primero para obtener información necesaria para iniciar sesión, luego un HttpPost para realizar el proceso de inicio de sesión real.HttpPost funciona en el proyecto Java, no en Android

El código siguiente funciona muy bien en un proyecto Java en Eclipse que tiene los siguientes archivos Jar en la trayectoria de la estructura: 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()); 
    } 
} 

El servidor (que no está bajo mi control) devuelve una redirección 302 cuando la entrada se ha realizado correctamente, y 200 si se produce un error y vuelve a cargar la página de inicio de sesión. Cuando se ejecutan con los archivos Jar anteriores, obtengo la redirección 302, sin embargo, si ejecuto exactamente el mismo código de un proyecto de Android con el archivo 1.6 Android Jar en la ruta de compilación recibo la respuesta 200 del servidor. Obtengo la misma respuesta 200 cuando ejecuto el código en mi dispositivo 2.2.

Mi aplicación para Android tiene permisos de internet y el HttpGet funciona bien. Asumo que el problema radica en el hecho de que HttpPost (o alguna otra clase) es diferente de alguna manera significativa entre la versión Android Jar y las versiones más nuevas de Apache.

He intentado agregar las bibliotecas de Apache a la ruta de compilación del proyecto de Android, pero debido a las clases duplicadas recibo mensajes como: INFO/dalvikvm(390): DexOpt: not resolving ambiguous class 'Lorg/apache/http/impl/client/DefaultHttpClient;' en el registro. También intenté usar un MultipartEntity en lugar del UrlEncodedFormEntity pero obtengo el mismo resultado de 200.

Por lo tanto, tengo algunas preguntas:
- ¿Puedo forzar el código que se ejecuta en Android para utilizar las bibliotecas Apache más nuevas en lugar de las versiones de Android?
- Si no, ¿alguien tiene alguna idea de cómo puedo alterar mi código para que funcione con Android Jar?
- ¿Hay algún otro enfoque totalmente diferente para hacer un HttpPost en Android?
- ¿Alguna otra idea?

he readalotofposts y code pero no voy a llegar a ninguna parte. Estuve atascado en esto por un par de días y no sé cómo hacer que la cosa funcione, así que intentaré cualquier cosa en este momento. Gracias por adelantado.

Respuesta

6

Ahora he renunciado a obtener la ruta HttpClient para dar la respuesta esperada desde el servidor cuando se ejecuta en Android. En su lugar reescribí el método doPost anterior para usar un HttpsURLConnection en su lugar. Aquí está la nueva versión (de trabajo) con la esperanza de que sea útil para alguien.

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

Todavía no tengo idea de por qué la forma HttpClient no funcionaba correctamente.

+1

buena respuesta. en Gingerbread y más tarde, HttpURLConnection es el camino a seguir. considere que Apache HttpClient está en desuso. –

0

¿Es posible que este sitio web detecte al usuario y de hecho arroje resultados diferentes porque es Android? Dado que 200 implica éxito, ¿por qué debe dar un 302 en lugar de un 200? ¿Ha imprimido el resultado que obtiene cuando devuelve 200 y proporciona alguna información adicional?

+0

El resultado 200 es sólo la página de inicio de sesión de usuario nuevo, con no hay mensajes de error u otra información, que es lo que normalmente sucede con un inicio de sesión incorrecto. Estoy configurando el user-agent de forma explícita en los encabezados, y está configurado de la misma manera que se llama el código. Puedo iniciar sesión en el sitio OK desde el navegador en mi teléfono Android, lo que implica que no está bloqueando en función del hecho de que es Android. –

0

Compruebe el RedirectHandler, anular la opción por defecto y hacer algo de tala en ella, he tenido problemas con que cuando se va a Android ...

+0

Estoy bastante contento con el código de redirección (que no incluí anteriormente), el problema es que ni siquiera llego tan lejos. Dado que el servidor devuelve un código 200 de Android en lugar del 302 devuelto por Eclipse, no estoy llegando a la parte donde necesito manejar el redireccionamiento. –

+0

Hum, ¿podría ser un problema de agente de usuario? – dacwe

+0

El agente de usuario se establece en el código anterior y se establece en el mismo valor, ya sea que se ejecute dentro de Android o como Java puro. He probado un agente de usuario de Android, un FF/Windows uno y algunos personalizados. Todos dan el mismo comportamiento. –

1

para evitar las colisiones utilizan este frasco para httpclient

httplib

y este post también serían muy útiles

stack overflow post

+0

ayudaría a alguien para uso futuro ... –

Cuestiones relacionadas