【问题标题】:ECONNRESET (Connection reset by peer) on a server with authentication具有身份验证的服务器上的 ECONNRESET(由对等方重置连接)
【发布时间】:2014-06-08 09:25:27
【问题描述】:

这是我的下载代码:

            File file = new File(dir, fileName);
            HttpClient httpclient = new DefaultHttpClient();
            HttpResponse response = httpclient.execute(downloadListHttpGet
                    .get(index));
            InputStream input = response.getEntity().getContent();
            OutputStream output = new FileOutputStream(
                    memoryDirectory + fileName);

            byte data[] = new byte[1024];
            int count;

            while ((count = input.read(data)) != -1) {

                    output.write(data, 0, count);

            }

            output.flush();
            output.close();
            input.close();

此代码工作正常,但使用经过身份验证的服务器,从下载开始近 40 秒后,我得到“ECONNRESET(对等连接重置)”异常。我认为它发生在“input.read(data)”部分。找了好多!!!有人说是服务器故障。这可能是真的,但我必须在客户端解决这个问题。我试图在“catch”块中运行新线程,但有一个问题:发生异常时,它不会立即进入“catch”块,大约需要 2 分钟。我试过这个解决方案: Getting "SocketException : Connection reset by peer" in Android 但它不起作用。

【问题讨论】:

    标签: android authentication download httpclient httpresponse


    【解决方案1】:

    尝试使用getHttpClient()这个类,而不是new DefaultHttpClient()

    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.HostnameVerifier;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.TrustManager;
    import javax.net.ssl.X509TrustManager;
    
    import org.apache.http.HttpVersion;
    import org.apache.http.client.HttpClient;
    import org.apache.http.client.params.HttpClientParams;
    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.conn.ssl.X509HostnameVerifier;
    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.HttpConnectionParams;
    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 static int ConnectionTimeoutInSeconds = 45;
        public static boolean DisableSSLcertificateCheck = true;
    
        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 java.security.cert.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 HttpClient getHttpClient() {
            try {
    
                HttpParams params = new BasicHttpParams();
    
                // Turn off stale checking.  Our connections break all the time anyway,
                // and it's not worth it to pay the penalty of checking every time.
                HttpConnectionParams.setStaleCheckingEnabled(params, false);
    
                // Default connection and socket timeout of 20 seconds.  Tweak to taste.
                HttpConnectionParams.setConnectionTimeout(params, ConnectionTimeoutInSeconds * 1000);
                HttpConnectionParams.setSoTimeout(params, ConnectionTimeoutInSeconds * 1000);
                HttpConnectionParams.setSocketBufferSize(params, 8192);
    
                // Don't handle redirects -- return them to the caller.  Our code
                // often wants to re-POST after a redirect, which we must do ourselves.
                HttpClientParams.setRedirecting(params, false);
    
                SSLSocketFactory mySSLSocketFactory = SSLSocketFactory.getSocketFactory();
    
                // disable ssl check on debug
                if (DisableSSLcertificateCheck ) {
                    KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
                    trustStore.load(null, null);
                    mySSLSocketFactory = new MySSLSocketFactory(trustStore);
                    HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
                    mySSLSocketFactory.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);
                }
    
                SchemeRegistry schemeRegistry = new SchemeRegistry();
                schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
                schemeRegistry.register(new Scheme("https", mySSLSocketFactory, 443));
                ClientConnectionManager manager = new ThreadSafeClientConnManager(params, schemeRegistry);
    
                return new DefaultHttpClient(manager, params);
            } catch (Exception e) {
                return new DefaultHttpClient();
            }
        }
    
    }
    

    它处理 SSL,使您可以忽略 SSL 证书并允许您手动更改超时。 我将从“禁用 ssl 检查”开始并将超时设置为 90(秒)。

    您可能尝试的另一种身份验证方式与 Bing 搜索 API 身份验证的工作方式相同(您需要下载并包含 commons-codec-1.9.jar):

    public class SearchAsyncTask extends AsyncTask<Void, Void, Void> {
    
    private final String TAG = getClass().getName();
    
    @Override
    protected Void doInBackground(Void... params) {
        try {
            String bingUrl = "https://api.datamarket.azure.com/Bing/SearchWeb/v1/Web?Query=pinhassi";
    
            String accountKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
            byte[] accountKeyBytes = Base64.encodeBase64((accountKey + ":" + accountKey).getBytes());
            String accountKeyEnc = new String(accountKeyBytes);
    
            URL url = null;
            url = new URL(bingUrl);
    
            URLConnection urlConnection = url.openConnection();
            urlConnection.setRequestProperty("Authorization", "Basic " + accountKeyEnc);
            InputStream response = urlConnection.getInputStream();
            String res = readStream(response);
            Log.d(TAG, res);
            //conn.disconnect();
    
        } catch (Exception e) {
            e.printStackTrace();
            Log.e(TAG, e.getMessage());
        }
    
        return null;
    }
    
    private String readStream(InputStream in) {
        BufferedReader reader = null;
        StringBuilder sb = new StringBuilder();
        try {
            reader = new BufferedReader(new InputStreamReader(in));
            String line = "";
            while ((line = reader.readLine()) != null) {
                //System.out.println(line);
                sb.append(line + "\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return sb.toString();
    }
    
    }
    

    【讨论】:

    • 谢谢。我不在我的代码中使用 KeyStore。我的身份验证是这样的:httpGet.setHeader("Authorization", "Bearer" + token) 然后我将 httpGet 传递给 httpclient.execute()。我该怎么办?
    • 我也不了解 GlobalData。请帮帮我。
    • 我删除了 GlobalData 并将其设置为变量“DisableSSLcertificateCheck”。
    • 我删除了 GlobalData 并将其设置为变量“DisableSSLcertificateCheck”。忽略 KeyStore 参数,只需调用静态方法 getHttpClient()。关于标题 - 我认为您的问题可能存在。我不知道您的服务器希望您发送什么样的授权以及如何发送:也许您应该将其作为 post param 发送而不是获取?也许作为获取参数,以 www.xyz.com/?Authorization="Bearer" 的形式。试着先弄清楚...
    猜你喜欢
    • 2019-03-25
    • 1970-01-01
    • 1970-01-01
    • 2011-12-30
    • 2012-01-05
    • 1970-01-01
    • 2020-09-01
    • 1970-01-01
    • 2013-01-05
    相关资源
    最近更新 更多