2010-02-12 12 views
37

Ho una classe di helper piuttosto semplice che sto usando per fare tutte le mie cose Get/Post Http. Sto usando HttpGet, HttpPost e HttpClient dalla libreria org.apache.http. Tutte le mie cose funzionano bene su HTTP, ma non appena ho provato a utilizzare un servizio che funziona su HTTPS, ottengo un ClientProtocolException quando eseguo la richiesta. L'unico messaggio nell'eccezione è "Il server non è riuscito a rispondere con una risposta HTTP valida".Posta HTTP sicura in Android

Per testare, ho inviato lo stesso payload esatto da un browser utilizzando un semplice modulo html e Fiddler2 utilizzando RequestBuilder. Ho inviato payload non validi e vuoti e persino inviato tutto quanto sopra con e senza intestazioni per vedere se c'era qualcosa di strano nel modo in cui gli oggetti stavano costruendo la richiesta.

Tutto ciò che ho usato nei test mi dà una risposta HTTP 200 valida. Il servizio mi fornisce solo una struttura che descrive l'errore se gli dò qualcosa di diverso da quello che si aspetta.

C'è qualcosa di speciale che devo aggiungere agli oggetti HttpPost o HttpClient per dirgli di usare HTTPS? Devo dire esplicitamente di usare una porta diversa?

EDIT:

ho infatti registrato la fabbrica presa sbagliata per la comunicazione HTTPS. Ecco il metodo aggiornata che uso per creare il mio oggetto HttpClient con la corretta presa di fabbrica nel caso in cui qualcuno cerca di questo tipo di problema in 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

Hi Rich, Grazie per il tuo post, è praticamente l'unica cosa su https su Android restituito da google. Dove hai ricevuto le informazioni per scrivere il codice che mostri qui? Inoltre, potresti spiegare il motivo per cui hai chiamato set version, charset e quel parametro? Per impostazione predefinita non sono assegnati i valori normali? Un'altra domanda: stai importando org.apache.http.conn.ssl.SSLSocketFactory, giusto? Grazie per chiarire questo –

+0

Sono abbastanza sicuro che questo è venuto dal libro Pro Android su Apress. Il libro non è stato grandioso, ma il capitolo sulla comunicazione http ha avuto una grande discussione sulla progettazione pratica quando un'app deve effettuare molte chiamate web. – Rich

risposta

36

Io non sono sicuro perché non è possibile gestire HTTPS . Ho scritto una classe di supporto per le mie applicazioni personali e sono in grado di ottenere GET/POST su HTTPS senza problemi. Inserirò il codice qui e forse puoi vedere se ci sono differenze tra il mio codice e il tuo.

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

grazie per quello. Ho avuto un bug nel mio codice per creare il mio oggetto HttpClient (pubblicato sopra) – Rich

+1

@MattC, non vedo dove si sta definendo esplicitamente per usare 'Https' o Port 443 ... mi manca qualcosa? Sembra una normale connessione HTTP .. – Cody

+0

@DoctorOreo E 'passato molto tempo da quando ho visto quel codice. Ricordo che gestiva correttamente HTTPS, ma da allora il framework è cambiato molto quindi dovrei tornare indietro e verificare. Scusa, non potrei essere più d'aiuto. – MattC

1

Come alcuni dei metodi sono deprecati, non dovrebbe essere così?

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

Devo cambiare qualcos'altro, come HttpVersion?

+1

Sì. Questo è stato pubblicato più di due anni fa, ma in questi giorni AndroidHttpClient.newInstance fa esattamente la stessa cosa – Rich

+0

Sì, questo non funziona su Android – JPM

Problemi correlati