2012-04-27 5 views
12

Używam HttpClient dla żądań HTTPS, który działa dobrze do tej pory. Po uaktualnieniu do usługi ICS niektórzy użytkownicy zgłaszają problemy z połączeniami 3G.Android: Schemat "http" niezarejestrowany w ICS 4.0.4 w/proxy

EDYCJA: Większość z nich wydaje się używać proxy, i mogę odtworzyć to lokalnie z T-Mobile SIM przy użyciu ich proxy.

Kłody mają ten ślad stosu:

java.lang.IllegalStateException: Scheme 'http' not registered. 
org.apache.http.conn.scheme.SchemeRegistry.getScheme(SchemeRegistry.java:80) 
org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:126) 
org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164) 
org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119) 
org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:360) 
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555) 
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487) 
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465) 

Naszym punktem końcowym HTTPS tylko, więc nie zarejestrować końcowy HTTP w naszej SchemeRegistry celowo. Nie ma nigdzie (AFAIK), gdzie przekierowujemy do HTTP.

Oto kod, który konfiguruje httpclient dla klienta https:

DefaultHttpClient ret = null; 

    // sets up parameters 
    HttpParams params = new BasicHttpParams(); 
    HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); 
    HttpProtocolParams.setContentCharset(params, "utf-8"); 
    params.setBooleanParameter("http.protocol.expect-continue", false); 

    HttpConnectionParams.setConnectionTimeout(params, DEFAULT_CONN_TIMEOUT_MSEC); 
    HttpConnectionParams.setSoTimeout(params, timeoutMsec); 
    HttpConnectionParams.setStaleCheckingEnabled(params, true); 

    SchemeRegistry registry = new SchemeRegistry(); 
    final SocketFactory sslSocketFactory = getPreferredSSLSocketFactory(); 
    registry.register(new Scheme("https", sslSocketFactory, 443)); 

    ThreadSafeClientConnManager manager = new ThreadSafeClientConnManager(params, registry); 
    ret = new DefaultHttpClient(manager, params); 
    // for preemptive authentication 
    // http://dlinsin.blogspot.com/2009/08/http-basic-authentication-with-android.html 
    ret.addRequestInterceptor(preemptiveAuth, 0); 
    ret.setCookieStore(communalCookieJar); 

    SimpleCredentialsProvider credProvider = new SimpleCredentialsProvider(getAccountPreferences()); 
    ret.setCredentialsProvider(credProvider); 

    return ret; 

Uwaga: Dzielimy tę instancję httpclient wśród wielu wątków.

Odpowiedz

3

Kwestia wydawało się, że niektórzy przewoźnicy pchały definicje nieprawidłowe proxy z aktualizacją 4.0.4. To przełamało HTTPS, ale HTTP działało poprawnie (na przykład Google Play nie działało).

Jedną z możliwych poprawek (oprócz poprawienia nieprawidłowego wpisu proxy) jest złapanie IllegalStateException podczas wykonywania żądań HttpClient i ustawienia flagi. Ten kod pominie dowolne proxy:

hc = new DefaultHttpClient(manager, params); 
    if (BYPASS_PROXY) 
     hc.setRoutePlanner(new DefaultHttpRoutePlanner(registry)); 
+7

Co to jest BYPASS_PROXY? Dlaczego nie zawsze możemy skorzystać z tego planowania trasy? Czy to rozwiązanie jest bezpieczne (np. Czy nadal będzie używać https)? –

+0

Twój kod działa. Właśnie zaczęło się to dziać dla mnie tylko przez 3G (Telenor, Szwecja). Czy istnieje potencjalny problem z tym, że zawsze jest to możliwe? – apanloco

+0

Czy istnieje problem z włączeniem go zawsze? –

1

Nie utworzyłbym nowej SchemeRegistry. Wezmę domyślny z ThreadSafeClientConnManager.getSchemeRegistry(). W ten sposób prawdopodobnie zawiera on wszystkie już obsługiwane schematy.

Część http może pochodzić z pośrednika operatora.

+0

Czy możesz udostępnić szczegóły? Nie znalazłem sposobu na uzyskanie domyślnego rejestru schematów z poziomu wątku bezpiecznego lub menedżera połączeń jednego klienta. – apanloco

+0

co masz na myśli? czy 'manage.getSchemeRegistry()' nie osiąga tego? – njzk2

+0

ThreadSafeClientConnManager i SingleClientConnManager REQUIRE a SchemeRegistry w konstruktorze, więc po prostu otrzymasz to, co MUSISZ podać, aby to zrobić. – apanloco

6

Z twojego stacktrace sugerowałbym zarejestrowanie obu (http, https) i sprawdzenie, czy to nie działa.

Powinieneś być w stanie debugować go, włączając słoiki ze źródłami Apache - przejdź do śledzenia @ SchemeRegistry.getScheme().

This wątek może pomóc.

Poniżej jest testowany na ICS OK ... Sample SSL ConnectionMgr na androidhttpclient libs:

static X509TrustManager tm = new X509TrustManager() { 

     public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException { 
     } 

     public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException { 
     } 

     public X509Certificate[] getAcceptedIssuers() { 
     return null; 
     } 
}; 

MyConnectionManager(SchemeRegistry scheme){ 
    super(scheme); 
} 

public static MyConnectionManager getInstance() { 
    if (instance == null){ 

     SSLContext ctx=null; 
     try { 
      ctx = SSLContext.getInstance("TLS"); 
      ctx.init(null, new TrustManager[]{tm}, null); 
     } catch (NoSuchAlgorithmException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (KeyManagementException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     }     
     SchemeRegistry schemeRegistry = new SchemeRegistry(); 
     schemeRegistry.register(new Scheme("http", 80,PlainSocketFactory.getSocketFactory())); 
     schemeRegistry.register(new Scheme("https", 443, SSLSocketFactory.getSocketFactory())); 
     instance = new MyConnectionManager(schemeRegistry); 
     // Increase max total connection to 200 
     instance.setMaxTotal(15); 
     // Increase default max connection per route to 20 
     instance.setDefaultMaxPerRoute(15); 
     // Increase max connections for localhost:80 to 50 
     HttpHost localhost = new HttpHost("picasaweb.google.com", 443); 
     instance.setMaxForRoute(new HttpRoute(localhost), 10); 
    } 
    return instance; 
}