Java 从Android应用程序与服务器通信时出现各种HTTPs错误

Java 从Android应用程序与服务器通信时出现各种HTTPs错误,java,android,apache,ssl,nginx,Java,Android,Apache,Ssl,Nginx,更新:2015年1月4日 我仍然有这些问题。我们应用程序的用户增加了,我看到了 所有类型的网络错误。我们的应用程序每次都会发送电子邮件 是应用程序上的网络相关错误 我们的应用程序不支持金融交易,因此重新提交不是真的 幂等-非常害怕启用HttpClient的重试功能。 我们在服务器上做了一些响应缓存来处理 重新提交由用户显式完成。然而,仍然没有解决办法 在没有不良用户体验的情况下工作 原始问题 我有一个android应用程序,作为用户操作的一部分发布数据。数据中包含少量图像&我将它们打包为Prot

更新:2015年1月4日

我仍然有这些问题。我们应用程序的用户增加了,我看到了 所有类型的网络错误。我们的应用程序每次都会发送电子邮件 是应用程序上的网络相关错误

我们的应用程序不支持金融交易,因此重新提交不是真的 幂等-非常害怕启用HttpClient的重试功能。 我们在服务器上做了一些响应缓存来处理 重新提交由用户显式完成。然而,仍然没有解决办法 在没有不良用户体验的情况下工作

原始问题

我有一个android应用程序,作为用户操作的一部分发布数据。数据中包含少量图像&我将它们打包为Protobuf消息(实际上是字节数组),并通过HTTPS连接将其发布到服务器

虽然该应用程序在大部分情况下运行良好,但我们偶尔会看到连接错误。现在,我们有一些用户处于相对较慢的网络区域(2G连接),这一问题变得更加突出。然而,这个问题并不局限于连接速度慢的地区,而是存在于使用WiFi和3G连接的客户身上

以下是我们在应用程序日志中注意到的少数例外情况

下面一个发生在5分钟后,因为我已经将套接字超时设置为5分钟。在本例中,应用程序试图发布145kb的数据

堆栈跟踪java.net.SocketTimeoutException:读取超时 位于org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_read(本机 (方法) 位于org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$SSLInputStream.read(OpenSSLSocketImpl.java:662) 位于org.apache.http.impl.io.AbstractSessionInputBuffer.fillBuffer(AbstractSessionInputBuffer.java:103) 位于org.apache.http.impl.io.AbstractSessionInputBuffer.readLine(AbstractSessionInputBuffer.java:191)

低于1发生2.5分钟(套接字超时设置为5分钟),客户端发送144kb的数据

javax.net.ssl.SSLException:写入错误:ssl=0x5e4f4640:I/O错误 在系统调用期间,管道断开 请访问org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_write(Native (方法) 位于org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$SSLOutputStream.write(OpenSSLSocketImpl.java:704) 位于org.apache.http.impl.io.AbstractSessionOutputBuffer.write(AbstractSessionOutputBuffer.java:109) 位于org.apache.http.impl.io.ContentLengthOutputStream.write(ContentLengthOutputStream.java:113)

1分钟后发生了低于1的情况

堆栈跟踪javax.net.ssl.SSLException:对等方关闭的连接 位于org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_do_handshake(本机 (方法) 位于org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:378) 位于org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$SSLInputStream(OpenSSLSocketImpl.java:634) 位于org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.getInputStream(OpenSSLSocketImpl.java:605)

77秒后发生了低于1的情况

堆栈跟踪javax.net.ssl.SSLException:ssl握手中止: ssl=0x5e2baf00:系统调用期间发生I/O错误,对等方重置连接 位于org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_do_handshake(本机 (方法) 位于org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:378) 位于org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$SSLInputStream(OpenSSLSocketImpl.java:634) 位于org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.getInputStream(OpenSSLSocketImpl.java:605) 位于org.apache.http.impl.io.SocketInputBuffer。(SocketInputBuffer.java:70)

15秒后发生以下情况(连接超时设置为15秒)

所用时间:15081堆栈跟踪 org.apache.http.conn.ConnectTimeoutException:连接到 /103.xx.xx.xx:443超时 位于org.apache.http.conn.scheme.PlainSocketFactory.connectSocket(PlainSocketFactory.java:121) 位于org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:144) 位于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:365)

下面是我用来发布Request的源代码片段

HttpParams params = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(params, 15000); //15 seconds
HttpConnectionParams.setSoTimeout(params, 300000); // 5 minutes

HttpClient client = getHttpClient(params);
HttpPost post = new HttpPost(uri);
post.setEntity(new ByteArrayEntity(requestByteArray));
HttpResponse httpResponse = client.execute(post);

    ....

public static HttpClient getHttpClient(HttpParams params) {
    try {
        KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
        trustStore.load(null, null);

        SSLSocketFactory sf = new TrustAllCertsSSLSocketFactory(trustStore);
        sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);


        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);
        DefaultHttpClient client = new DefaultHttpClient(ccm, params);
        // below line of code will disable the retrying of HTTP request when connection is timed
        // out.

        client.setHttpRequestRetryHandler(new DefaultHttpRequestRetryHandler(0, false));
        return client;
    } catch (Exception e) {
        return new DefaultHttpClient();
    }
}
我读过一些论坛,指出我们应该使用HttpUrlConnection类。我确实做了代码更改以用作热修复程序。虽然它可以在我的三星手机上运行,但它似乎在用户使用的手机中存在一些问题,甚至无法连接到我们的网站。我不得不将它回滚,但如果根本原因可以锁定到DefaultHttpClient,我可以重新查看它

我们的web服务器是nginx,我们的web服务运行在ApacheTomcat上。 客户大多使用安卓4.1+手机。我从其手机中检索到上述堆栈跟踪信息的客户正在使用Micromax A110Q手机和Android 4.2.1

对此的任何意见都将不胜感激。非常感谢

更新:

  • 我注意到我们没有关闭连接管理器。所以在我使用http客户机的代码的最后一块中添加了下面的代码
  • 更新了nginx配置,以接受最大为5M的数据,因为其默认值为1Mb,一些客户端提交的数据超过1Mb,服务器正在断开连接,出现413错误
  • 还增加了nginx代理读取超时,使其等待从客户端获取数据的时间更长
  • 通过上述更改,错误有所减少。在过去一周中,我看到以下两种类型的错误:

  • org.apache.http.conn.ConnectTimeoutException:连接到/103.xx.xx.x
    
      if (client != null) {           client.getConnectionManager().shutdown();
      }
    
    client_max_body_size 5M;
    
    proxy_read_timeout 300;