13

我正在将 HttpClient 用于 HTTPS 请求,到目前为止它运行良好。升级到 ICS 后,一些用户报告连接 3G 连接时出现问题。

编辑:他们中的大多数人似乎都在使用代理,我可以使用他们的代理使用 T-Mobile SIM 在本地复制它。

日志有这个堆栈跟踪:

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)

我们的端点仅是 HTTPS,因此我们不会故意在 SchemeRegistry 中注册 HTTP 端点。没有任何地方(AFAIK)我们重定向到 HTTP。

下面是为 HTTPS 客户端设置 HttpClient 的代码:

    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;

注意:我们在多个线程之间共享这个 HttpClient 实例。

4

3 回答 3

6

从您的堆栈跟踪中,我建议您同时注册(http、https)并查看是否不起作用。

您应该能够通过包含 apache 源 jar 来调试它 - 深入跟踪 @SchemeRegistry.getScheme()。

这个线程可能会有所帮助。

下面在 ICS 上测试 OK... androidhttpclient库上的示例 SSL ConnectionMgr:

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;
}
于 2012-04-28T16:01:21.973 回答
3

问题似乎是一些运营商在 4.0.4 更新中推送了无效的代理定义。这破坏了 HTTPS,但 HTTP 正常工作(例如,Google Play 不工作)。

一种可能的解决方法(除了修复无效的代理条目)是在执行 HttpClient 请求时捕获 IllegalStateException 并设置一个标志。此代码将绕过任何代理:

    hc = new DefaultHttpClient(manager, params);
    if (BYPASS_PROXY)
        hc.setRoutePlanner(new DefaultHttpRoutePlanner(registry));
于 2012-05-10T19:08:59.337 回答
2

我不会创建新的 SchemeRegistry。我会从 ThreadSafeClientConnManager.getSchemeRegistry() 中获取默认值。这样,它可能包含各种已经支持的方案。

http 部分可以来自运营商的代理。

于 2012-04-27T16:14:30.850 回答