2010-02-12 19 views
37

Tengo una clase de ayuda bastante básica que estoy usando para hacer todas mis cosas de Http Get/Post. Estoy usando HttpGet, HttpPost y HttpClient de la biblioteca org.apache.http. Todas mis cosas funcionan bien a través de HTTP, pero tan pronto como intenté consumir un servicio que funciona a través de HTTPS, recibo una excepción ClientProtocolException al ejecutar la solicitud. El único mensaje en la excepción es "El servidor no respondió con una respuesta HTTP válida".Publicación HTTP segura en Android

Para probar, envié exactamente la misma carga desde un navegador usando un formulario html simple y Fiddler2 usando RequestBuilder. He enviado cargas útiles inválidas y vacías e incluso he enviado todo lo anterior con y sin encabezados para ver si había algo funky sobre la forma en que los objetos estaban creando la solicitud.

Todo lo que he usado en las pruebas me da una respuesta HTTP válida de 200 estados. El servicio solo me da una estructura que describe el error si le doy algo diferente a lo que espera.

¿Hay algo especial que deba agregar al objeto (s) HttpPost o HttpClient para indicarle que use HTTPS? ¿Tengo que decirle explícitamente que use un puerto diferente?

EDIT:

hecho que registró la fábrica de sockets mal para la comunicación https. Aquí está el método actualizado que utilizo para crear mi objeto HttpClient con la fábrica toma correcta por si acaso alguien busca este tipo de problemas en el futuro:

private HttpClient createHttpClient() 
{ 
    HttpParams params = new BasicHttpParams(); 
    HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); 
    HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET); 
    HttpProtocolParams.setUseExpectContinue(params, true); 

    SchemeRegistry schReg = new SchemeRegistry(); 
    schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); 
    schReg.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443)); 
    ClientConnectionManager conMgr = new ThreadSafeClientConnManager(params, schReg); 

    return new DefaultHttpClient(conMgr, params); 
} 
+0

Hola Rich, Gracias por su puesto, que es más o menos la única cosa sobre https en android devuelto por Google. ¿De dónde sacaste la información para escribir el código que muestras aquí? Además, ¿podría explicar el motivo de la llamada a la versión de conjunto, juego de caracteres y ese parámetro? ¿No están asignados por defecto los valores normales? Una pregunta más: está importando org.apache.http.conn.ssl.SSLSocketFactory, ¿verdad? Gracias por aclarar esto –

+0

Estoy bastante seguro de que esto vino del libro Pro Android en Apress. El libro no fue muy bueno, pero el capítulo sobre comunicación http tuvo una gran discusión sobre el diseño práctico cuando una aplicación necesita hacer muchas llamadas a la web. – Rich

Respuesta

36

No estoy seguro de por qué no puede manejar HTTPS . Escribí una clase de ayuda para mis propias aplicaciones y puedo GET/POST a HTTPS sin ningún problema. Publicaré el código aquí y quizás puedas ver si hay diferencias entre mi código y el tuyo.

import java.io.IOException; 
import java.io.InputStream; 
import java.io.UnsupportedEncodingException; 
import java.net.HttpURLConnection; 
import java.net.URL; 
import java.net.URLConnection; 

import org.apache.http.HttpResponse; 
import org.apache.http.client.methods.HttpGet; 
import org.apache.http.client.methods.HttpPost; 
import org.apache.http.client.params.ClientPNames; 
import org.apache.http.client.params.CookiePolicy; 
import org.apache.http.entity.StringEntity; 
import org.apache.http.impl.client.DefaultHttpClient; 
import org.apache.http.params.BasicHttpParams; 
import org.apache.http.params.HttpConnectionParams; 
import org.apache.http.params.HttpParams; 
import org.apache.http.protocol.BasicHttpContext; 
import org.apache.http.protocol.HttpContext; 
import org.apache.http.util.EntityUtils; 
import org.json.JSONObject; 

import android.util.Log; 

public class HttpRequest{ 

    DefaultHttpClient httpClient; 
    HttpContext localContext; 
    private String ret; 

    HttpResponse response = null; 
    HttpPost httpPost = null; 
    HttpGet httpGet = null; 

    public HttpRequest(){ 
     HttpParams myParams = new BasicHttpParams(); 

     HttpConnectionParams.setConnectionTimeout(myParams, 10000); 
     HttpConnectionParams.setSoTimeout(myParams, 10000); 
     httpClient = new DefaultHttpClient(myParams);  
     localContext = new BasicHttpContext();  
    } 

    public void clearCookies() { 
     httpClient.getCookieStore().clear(); 
    } 

    public void abort() { 
     try { 
      if (httpClient != null) { 
       System.out.println("Abort."); 
       httpPost.abort(); 
      } 
     } catch (Exception e) { 
      System.out.println("Your App Name Here" + e); 
     } 
    } 

    public String sendPost(String url, String data) { 
     return sendPost(url, data, null); 
    } 

    public String sendJSONPost(String url, JSONObject data) { 
     return sendPost(url, data.toString(), "application/json"); 
    } 

    public String sendPost(String url, String data, String contentType) { 
     ret = null; 

     httpClient.getParams().setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.RFC_2109); 

     httpPost = new HttpPost(url); 
     response = null; 

     StringEntity tmp = null;   

     Log.d("Your App Name Here", "Setting httpPost headers"); 

     httpPost.setHeader("User-Agent", "SET YOUR USER AGENT STRING HERE"); 
     httpPost.setHeader("Accept", "text/html,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"); 

     if (contentType != null) { 
      httpPost.setHeader("Content-Type", contentType); 
     } else { 
      httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded"); 
     } 

     try { 
      tmp = new StringEntity(data,"UTF-8"); 
     } catch (UnsupportedEncodingException e) { 
      Log.e("Your App Name Here", "HttpUtils : UnsupportedEncodingException : "+e); 
     } 

     httpPost.setEntity(tmp); 

     Log.d("Your App Name Here", url + "?" + data); 

     try { 
      response = httpClient.execute(httpPost,localContext); 

      if (response != null) { 
       ret = EntityUtils.toString(response.getEntity()); 
      } 
     } catch (Exception e) { 
      Log.e("Your App Name Here", "HttpUtils: " + e); 
     } 

     Log.d("Your App Name Here", "Returning value:" + ret); 

     return ret; 
    } 

    public String sendGet(String url) { 
     httpGet = new HttpGet(url); 

     try { 
      response = httpClient.execute(httpGet); 
     } catch (Exception e) { 
      Log.e("Your App Name Here", e.getMessage()); 
     } 

     //int status = response.getStatusLine().getStatusCode(); 

     // we assume that the response body contains the error message 
     try { 
      ret = EntityUtils.toString(response.getEntity()); 
     } catch (IOException e) { 
      Log.e("Your App Name Here", e.getMessage()); 
     } 

     return ret; 
    } 

    public InputStream getHttpStream(String urlString) throws IOException { 
     InputStream in = null; 
     int response = -1; 

     URL url = new URL(urlString); 
     URLConnection conn = url.openConnection(); 

     if (!(conn instanceof HttpURLConnection))      
      throw new IOException("Not an HTTP connection"); 

     try{ 
      HttpURLConnection httpConn = (HttpURLConnection) conn; 
      httpConn.setAllowUserInteraction(false); 
      httpConn.setInstanceFollowRedirects(true); 
      httpConn.setRequestMethod("GET"); 
      httpConn.connect(); 

      response = httpConn.getResponseCode();     

      if (response == HttpURLConnection.HTTP_OK) { 
       in = httpConn.getInputStream();         
      }      
     } catch (Exception e) { 
      throw new IOException("Error connecting");    
     } // end try-catch 

     return in;  
    } 
} 
+0

gracias por eso. Tuve un error en mi propio código para crear mi objeto HttpClient (publicado anteriormente) – Rich

+1

@MattC, no veo en qué definición explícitamente utilizas 'Https' o Port 443 ... ¿me falta algo? Esto parece una conexión HTTP normal. – Cody

+0

@DoctorOreo Ha pasado mucho tiempo desde que miré ese código. Recuerdo que manejaba HTTPS correctamente, pero el marco ha cambiado mucho desde entonces, así que tendría que volver atrás y verificarlo. Lo siento, no podría ser más ayuda. – MattC

1

Como algunos de los métodos están en desuso, ¿no debería ser así?

private DefaultHttpClient createHttpClient() { 
    HttpParams params = new BasicHttpParams(); 

    HttpConnectionParams.setConnectionTimeout(params, 10000); 
    HttpConnectionParams.setSoTimeout(params, 10000); 
    HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); 
    HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET); 
    HttpProtocolParams.setUseExpectContinue(params, true); 

    SchemeRegistry schReg = new SchemeRegistry(); 
    schReg.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory())); 
    schReg.register(new Scheme("https", 443, SSLSocketFactory.getSocketFactory())); 
    ClientConnectionManager conMgr = new PoolingClientConnectionManager(schReg); 

    return new DefaultHttpClient(conMgr, params); 
    } 

¿Debo cambiar algo más, como HttpVersion?

+1

Sí. Esto fue publicado hace más de dos años, pero en estos días AndroidHttpClient.newInstance hace esencialmente lo mismo – Rich

+0

Sí, esto no funciona en Android – JPM

Cuestiones relacionadas