Android中使用https连接如何处理IOException?

问题描述 投票:0回答:3

我使用支持 Https 的服务从服务器获取数据。这里我使用自签名方法来创建httpClient。应用程序工作正常,但有时我会收到 IOExcetion 并且我的 api 调用失败。我无法从服务器获取数据。我为我的 httpClient 使用了 ConnectionTimeOut、SocketTimeouts。我不明白为什么我的 api 调用在某些情况下失败。在使用 https:// api 调用时如何避免 IOException?

这里我附上了自签名流程的代码。

SSLFactory 类:

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 java.security.cert.X509Certificate[] getAcceptedIssuers() {
                 return null;
             }
                         

                         @Override
                         public void checkClientTrusted(
                                         java.security.cert.X509Certificate[] chain,
                                         String authType)
                                         throws java.security.cert.CertificateException {
                         }

                         @Override
                         public void checkServerTrusted(
                                         java.security.cert.X509Certificate[] chain,
                                         String authType)
                                         throws java.security.cert.CertificateException {
                         }
         };

         sslContext.init(null, new TrustManager[] { tm }, null);
     }
    @Override
    public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException {
        return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
    }

    @Override
    public Socket createSocket() throws IOException {
        return sslContext.getSocketFactory().createSocket();
    }
}

我的 httpClient 对象方法如下:

public HttpClient getNewHttpClient(boolean containsTimeout) {
        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);
            if(containsTimeout)
            {
                int timeout = 60000;
                HttpConnectionParams.setConnectionTimeout(params, timeout);

                HttpConnectionParams.setSoTimeout(params, timeout);
            }
            SchemeRegistry registry = new SchemeRegistry();
            registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
            registry.register(new Scheme("https", sf, 8443));
            ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
            return new DefaultHttpClient(ccm, params);
        } catch (Exception e) {
            return new DefaultHttpClient();
        }
    }

而我的api调用方法是

HttpClient httpclient = getNewHttpClient(true);
            HttpPost httppost = new HttpPost(url);
            httppost.setHeader("Content-Type", "text/xml");
        BasicHttpResponse httpResponse = null;
            httpResponse = (BasicHttpResponse) httpclient.execute(httppost);
        InputStream is = httpResponse.getEntity().getContent();

上面的代码中(InputStream)是我的最终结果。

我在 10 次迭代中至少有 2 次没有得到最终结果。如何避免 IOException?

android android-networking androidhttpclient
3个回答
0
投票

首先创建一个类名EasySSLSocketFactory

public class EasySSLSocketFactory implements SocketFactory,
        LayeredSocketFactory {

    private SSLContext sslcontext = null;

    private static SSLContext createEasySSLContext() throws IOException {
        try {
            SSLContext context = SSLContext.getInstance("TLS");
            context.init(null, new TrustManager[] { new EasyX509TrustManager(
                    null) }, null);
            return context;
        } catch (Exception e) {
            throw new IOException(e.getMessage());
        }
    }

    private SSLContext getSSLContext() throws IOException {
        if (this.sslcontext == null) {
            this.sslcontext = createEasySSLContext();
        }
        return this.sslcontext;
    }

    /**
     * @see org.apache.http.conn.scheme.SocketFactory#connectSocket(java.net.Socket,
     *      java.lang.String, int, java.net.InetAddress, int,
     *      org.apache.http.params.HttpParams)
     */
    public Socket connectSocket(Socket sock, String host, int port,
            InetAddress localAddress, int localPort, HttpParams params)
            throws IOException, UnknownHostException, ConnectTimeoutException {
        int connTimeout = HttpConnectionParams.getConnectionTimeout(params);
        int soTimeout = HttpConnectionParams.getSoTimeout(params);
        InetSocketAddress remoteAddress = new InetSocketAddress(host, port);
        SSLSocket sslsock = (SSLSocket) ((sock != null) ? sock : createSocket());

        if ((localAddress != null) || (localPort > 0)) {
            // we need to bind explicitly
            if (localPort < 0) {
                localPort = 0; // indicates "any"
            }
            InetSocketAddress isa = new InetSocketAddress(localAddress,
                    localPort);
            sslsock.bind(isa);
        }

        sslsock.connect(remoteAddress, connTimeout);
        sslsock.setSoTimeout(soTimeout);
        return sslsock;

    }

    /**
     * @see org.apache.http.conn.scheme.SocketFactory#createSocket()
     */
    public Socket createSocket() throws IOException {
        return getSSLContext().getSocketFactory().createSocket();
    }

    /**
     * @see org.apache.http.conn.scheme.SocketFactory#isSecure(java.net.Socket)
     */
    public boolean isSecure(Socket socket) throws IllegalArgumentException {
        return true;
    }

    /**
     * @see org.apache.http.conn.scheme.LayeredSocketFactory#createSocket(java.net.Socket,
     *      java.lang.String, int, boolean)
     */
    public Socket createSocket(Socket socket, String host, int port,
            boolean autoClose) throws IOException, UnknownHostException {
        return getSSLContext().getSocketFactory().createSocket(socket, host,
                port, autoClose);
    }

    // -------------------------------------------------------------------
    // javadoc in org.apache.http.conn.scheme.SocketFactory says :
    // Both Object.equals() and Object.hashCode() must be overridden
    // for the correct operation of some connection managers
    // -------------------------------------------------------------------

    public boolean equals(Object obj) {
        return ((obj != null) && obj.getClass().equals(
                EasySSLSocketFactory.class));
    }

    public int hashCode() {
        return EasySSLSocketFactory.class.hashCode();
    }

}

然后实施X509信任管理器

public class EasyX509TrustManager implements X509TrustManager {

    private X509TrustManager standardTrustManager = null;

    /**
     * Constructor for EasyX509TrustManager.
     */
    public EasyX509TrustManager(KeyStore keystore)
            throws NoSuchAlgorithmException, KeyStoreException {
        super();
        TrustManagerFactory factory = TrustManagerFactory
                .getInstance(TrustManagerFactory.getDefaultAlgorithm());
        factory.init(keystore);
        TrustManager[] trustmanagers = factory.getTrustManagers();
        if (trustmanagers.length == 0) {
            throw new NoSuchAlgorithmException("no trust manager found");
        }
        this.standardTrustManager = (X509TrustManager) trustmanagers[0];
    }

    /**
     * @see javax.net.ssl.X509TrustManager#checkClientTrusted(X509Certificate[],
     *      String authType)
     */
    public void checkClientTrusted(X509Certificate[] certificates,
            String authType) throws CertificateException {
        standardTrustManager.checkClientTrusted(certificates, authType);
    }

    /**
     * @see javax.net.ssl.X509TrustManager#checkServerTrusted(X509Certificate[],
     *      String authType)
     */
    public void checkServerTrusted(X509Certificate[] certificates,
            String authType) throws CertificateException {
        if ((certificates != null) && (certificates.length == 1)) {
            certificates[0].checkValidity();
        } else {
            standardTrustManager.checkServerTrusted(certificates, authType);
        }
    }

    /**
     * @see javax.net.ssl.X509TrustManager#getAcceptedIssuers()
     */
    public X509Certificate[] getAcceptedIssuers() {
        return this.standardTrustManager.getAcceptedIssuers();
    }

}

现在您可以获取您的内容了

public class GetContent{

    private ClientConnectionManager clientConnectionManager = null;
    private HttpContext context = null;
    private HttpParams params = null;

    public GetContent() {
        setup();
    }

    private HttpResponse getResponseFromUrl(String url) {

        HttpResponse response = null;
        try {

            HttpConnectionParams.setConnectionTimeout(params, 300000);
            HttpConnectionParams.setSoTimeout(params, 300000);

            // connection (client has to be created for every new connection)
            HttpClient client = new DefaultHttpClient(clientConnectionManager,
                    params);
            HttpGet get = new HttpGet(url);

            response = client.execute(get, context);

        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();

        }
        return response;
    }

    public ClientConnectionManager getClientConnectionManager() {
        return clientConnectionManager;
    }

    public HttpParams getHttpParams() {
        return params;
    }

    public HttpContext getHttpContext() {
        return context;
    }

    public InputStream getInputStream(final Context context, String url) {

        InputStream is = null;

        try {

            HttpResponse response = getResponseFromUrl(url);
            if (response != null) {
                HttpEntity entity = response.getEntity();

                if (entity != null) 

                    is = entity.getContent();

                    return is;
                   }
        } catch (ClientProtocolException e) {

            Log.e("log_tag", "Error in http connection " + e.toString());
            return null;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } catch (JSONException e) {
            Log.e("log_tag", "Error parsing data " + e.toString());
            return null;
        }

        return null;

    }

    private final void setup() {

        SchemeRegistry schemeRegistry = new SchemeRegistry();

        // http scheme
        schemeRegistry.register(new Scheme("http", PlainSocketFactory
                .getSocketFactory(), 80));
        // https scheme
        schemeRegistry.register(new Scheme("https", new EasySSLSocketFactory(),
                443));

        params = new BasicHttpParams();
        params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 1);
        params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE,
                new ConnPerRouteBean(1));
        params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false);

        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
        HttpProtocolParams.setContentCharset(params, "utf8");

        CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        // set the user credentials for our site "example.com"
        credentialsProvider.setCredentials(new AuthScope("example.com",
                AuthScope.ANY_PORT), new UsernamePasswordCredentials(
                "UserNameHere", "UserPasswordHere"));
        clientConnectionManager = new ThreadSafeClientConnManager(params,
                schemeRegistry);

        context = new BasicHttpContext();
        context.setAttribute("http.auth.credentials-provider",
                credentialsProvider);

    }

}

这是如何获取InputStream

GetContent content =new GetContent();
InputStream is = content.getInputStream(this,MY_URL);

0
投票

使用这样的东西

public void someMethod() throws IOException {
try {
 //  Do your work
} catch (MyException e){
throw new IOException(e.toString());
// or you can retry the same thing here without showing error
}
}

0
投票

只需将代码放入 try catch 中即可

 try {
       HttpClient httpclient = getNewHttpClient(true);
        HttpPost httppost = new HttpPost(url);
        httppost.setHeader("Content-Type", "text/xml");
    BasicHttpResponse httpResponse = null;
        httpResponse = (BasicHttpResponse) httpclient.execute(httppost);
    InputStream is = httpResponse.getEntity().getContent();


    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    } catch (ClientProtocolException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
© www.soinside.com 2019 - 2024. All rights reserved.