【问题标题】:Android HTTPS Post - Not workingAndroid HTTPS 发布 - 不工作
【发布时间】:2012-01-03 13:51:18
【问题描述】:

我已经尝试了很长时间来让它工作 - 但无论我做什么,我的 HTTP*S* POST 总是产生 HttpUtils: javax.net.ssl.SSLException: Not trusted server certificate

基本上我关注了这个tutorial

  • 我成功地从 服务器。
  • 我使用 Bouncy Castle 从证书成功创建了一个密钥库
  • 我未能实现自定义 Apache HttpClient。这是我的 代码:

    import android.content.Context;
    import org.apache.http.conn.ClientConnectionManager;
    import org.apache.http.conn.scheme.PlainSocketFactory;
    import org.apache.http.conn.scheme.Scheme;
    import org.apache.http.conn.scheme.SchemeRegistry;
    import org.apache.http.conn.ssl.SSLSocketFactory;
    import org.apache.http.impl.client.DefaultHttpClient;
    import org.apache.http.impl.conn.SingleClientConnManager;
    import org.apache.http.params.HttpParams;
    import java.io.InputStream;
    import java.security.KeyStore;
    
    public class MyHttpClient extends DefaultHttpClient {
      final Context context;
    
      public MyHttpClient(Context context) {
        this.context = context;
      }
    
      public MyHttpClient(Context context2, HttpParams myParams) {
          super(myParams);
          this.context= context2;
    }
    
    @Override protected ClientConnectionManager createClientConnectionManager() {
        SchemeRegistry registry = new SchemeRegistry();
        registry.register(
            new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        registry.register(new Scheme("https", newSslSocketFactory(), 443));
        return new SingleClientConnManager(getParams(), registry);
      }
    
      private SSLSocketFactory newSslSocketFactory() {
        try {
          KeyStore trusted = KeyStore.getInstance("BKS");
          InputStream in = context.getResources().openRawResource(R.raw.mystore);
          try {
            trusted.load(in, "password".toCharArray());
          } finally {
            in.close();
          }
          return new SSLSocketFactory(trusted);
        } catch (Exception e) {
          throw new AssertionError(e);
        }
      }
    }
    

    在我构造 POST 的 HTTP 请求类中:

    public class HttpRequest {
    MyHttpClient httpClient;
    HttpContext localContext;
    private String ret;
    
    HttpResponse response = null;
    HttpPost httpPost = null;
    HttpGet httpGet = null;
    
    public HttpRequest(Context context){
        HttpParams myParams = new BasicHttpParams();
    
        HttpConnectionParams.setConnectionTimeout(myParams, 10000);
        HttpConnectionParams.setSoTimeout(myParams, 10000);
        httpClient = new MyHttpClient(context, myParams);       
        localContext = new BasicHttpContext();    
    }
    
    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;        
    
        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("Log", "HttpUtils : UnsupportedEncodingException : "+e);
        }
    
        httpPost.setEntity(tmp);
    
        try {
            response = httpClient.execute(httpPost,localContext);
    
            if (response != null) {
                ret = EntityUtils.toString(response.getEntity());
            }
        } catch (Exception e) {
            Log.e("Log", "HttpUtils: " + e);
        }
    
        return ret;
    }
    }
    

我的 POST 适用于非 https 网站。任何帮助将不胜感激。

【问题讨论】:

    标签: android post ssl https


    【解决方案1】:

    有时 https url 在 android webview 中显示空白屏幕。这是因为您必须信任 ssl 认证,或者您需要覆盖 webview 客户端中的 ssl 错误。

    以下 webview 客户端提供访问 https url 所需的功能。 这里 shouldOverrideUrlLoading 用于允许 webview 内的重定向 url,onReceivedSslError 这个忽略 SSL 证书错误来访问 https url。


    Webview客户端:

    private class MyWebViewClient extends WebViewClient 
                 {
            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                System.out.println("onPageStarted: " + url);
            }
    
            @Override
            public boolean shouldOverrideUrlLoading(WebView webView, String url) {
                System.out.println("shouldOverrideUrlLoading: " + url); 
                webView.loadUrl(url);
                return true;
            }
    
            @Override
            public void onPageFinished(WebView webView, String url) {
                System.out.println("onPageFinished: " + url);               
    
            }
    
            @Override
            public void onReceivedSslError(WebView view, SslErrorHandler handler,
                    SslError error) {
                handler.proceed(); // Ignore SSL certificate errors
            }   
    
        }
    

    【讨论】:

    • 仅使用上面示例中的 OnReceivedSslError(...) 方法,它就可以很好地传递 cookie。这节省了我的时间,非常感谢!
    【解决方案2】:

    使用此类获取您的 HttpClient。并检查它是否有帮助。

    包 com.android.MyCellFamily.DAHttp;

    import java.io.IOException;
    import java.net.Socket;
    import java.net.UnknownHostException;
    import java.security.KeyManagementException;
    import java.security.KeyStore;
    import java.security.KeyStoreException;
    import java.security.NoSuchAlgorithmException;
    import java.security.UnrecoverableKeyException;
    import java.security.cert.CertificateException;
    import java.security.cert.X509Certificate;
    
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.TrustManager;
    import javax.net.ssl.X509TrustManager;
    
    import org.apache.http.HttpVersion;
    import org.apache.http.conn.ClientConnectionManager;
    import org.apache.http.conn.scheme.PlainSocketFactory;
    import org.apache.http.conn.scheme.Scheme;
    import org.apache.http.conn.scheme.SchemeRegistry;
    import org.apache.http.conn.ssl.SSLSocketFactory;
    import org.apache.http.impl.client.DefaultHttpClient;
    import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
    import org.apache.http.params.BasicHttpParams;
    import org.apache.http.params.HttpParams;
    import org.apache.http.params.HttpProtocolParams;
    import org.apache.http.protocol.HTTP;
    
    public class MySSLSocketFactory extends SSLSocketFactory {
        SSLContext sslContext = SSLContext.getInstance("TLS");
    
        public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
            super(truststore);
    
            TrustManager tm = new X509TrustManager() {
                public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                }
    
                public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                }
    
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            };
    
            sslContext.init(null, new TrustManager[] { tm }, null);
        }
    
        @Override
        public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
            return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
        }
    
        @Override
        public Socket createSocket() throws IOException {
            return sslContext.getSocketFactory().createSocket();
        }
    
    
    public static DefaultHttpClient getNewHttpClient() {
        try {
            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            trustStore.load(null, null);
    
            SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
            sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    
            HttpParams params = new BasicHttpParams();
            HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
            HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
    
            SchemeRegistry registry = new SchemeRegistry();
            registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
            registry.register(new Scheme("https", sf, 443));
    
            ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
    
            return new DefaultHttpClient(ccm, params);
        } catch (Exception e) {
            return new DefaultHttpClient();
        }
    }
    }
    

    【讨论】:

      【解决方案3】:

      查看错误信息:

      HttpUtils: javax.net.ssl.SSLException: 不受信任的服务器证书

      这正是它所说的——服务器没有使用受信任的证书。我敢打赌,如果您尝试使用 Firefox 或 IE 访问同一服务器,您会遇到类似的错误。

      【讨论】:

      • Android 制造商信任的证书很少(可能是普通证书的一半?),并且当浏览器未运行时(例如在 web 视图中或在原始问题中),将不会弹出问题询问最终用户接受不受信任的证书。因此,您必须在您自己的代码中修复此问题,如下面的两个示例所示。
      猜你喜欢
      • 2010-10-01
      • 2013-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-05
      • 2018-12-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多