2014-12-02 78 views
1

我試圖打一些外部API來獲取一些數據。當數據量很小時,一切正常,但是當API返回的數據量很大時,我會得到一個例外情況:CONNECTION RESET例外。下面的代碼是從java類InterfaceHelper和我也標記了註釋在行我沒有在哪裏得到異常[它試圖從InputStream]讀取數據]。java.net.SocketException:使用HTTPConnection重置連接

我試圖在STACKOVERFLOW本身上搜索這麼多問題,但沒有找到合適的答案。所以請不要將其標記爲重複的問題。我想知道這個問題背後的原因是什麼,這個問題的解決方案是什麼。如果您發現此問題爲重複,請在將其標記爲重複之前回答。我賭你。

查找下面我已經使用過的代碼。由於安全原因,URL是一些虛擬網址,我無法提及我使用的實際URL。

try{ 
     URL url = new URL("http://example.com/someParams/SOME-ACCESS-TOKEN"); 
     HttpURLConnection connection = (HttpURLConnection)url.openConnection(); 
     connection.setRequestMethod("GET"); 
     connection.setRequestProperty("Content-Type","application/x-www-form-urlencoded"); 
     connection.setRequestProperty("Content-Language", "en-US"); 
     connection.setRequestProperty("X-EXAMPLE-LOGIN", "XXXXXXXX"); 
     connection.setRequestProperty("X-EXAMPLE-PASSWORD", "XXXXXX"); 
     connection.setUseCaches(false); 
     connection.setDoInput(true); 
     connection.setDoOutput(true); 
     DataInputStream input = new DataInputStream(connection.getInputStream()); 
     String ret = ""; 
     if(input!=null){ 
      for(int c = input.read(); c != -1; c = input.read()) { //InterfaceHelper.java:695 
       ret = ret + String.valueOf((char)c); 
      } 
     } 

     if(input!=null) 
      input.close(); 
     if(connection!=null) 
      connection.disconnect(); 

       if(ret!=null && ret.length()>0){ 
        return ret; 
       } 

    }catch(Exception e) { 
     e.printStackTrace(); 
    } 

這個例外,我得到

 java.net.SocketException: Connection reset 
     at java.net.SocketInputStream.read(SocketInputStream.java:196) 
     at java.net.SocketInputStream.read(SocketInputStream.java:122) 
     at sun.security.ssl.InputRecord.readFully(InputRecord.java:442) 
     at sun.security.ssl.InputRecord.readV3Record(InputRecord.java:554) 
     at sun.security.ssl.InputRecord.read(InputRecord.java:509) 
     at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:927) 
     at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:884) 
     at sun.security.ssl.AppInputStream.read(AppInputStream.java:102) 
     at java.io.BufferedInputStream.fill(BufferedInputStream.java:235) 
     at java.io.BufferedInputStream.read1(BufferedInputStream.java:275) 
     at java.io.BufferedInputStream.read(BufferedInputStream.java:334) 
     at sun.net.www.http.ChunkedInputStream.fastRead(ChunkedInputStream.java:244) 
     at sun.net.www.http.ChunkedInputStream.read(ChunkedInputStream.java:689) 
     at java.io.FilterInputStream.read(FilterInputStream.java:133) 
     at sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:3053) 
     at sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:3047) 
     at sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:3035) 
     at java.io.FilterInputStream.read(FilterInputStream.java:83) 
     at com.lsa.akosha.util.InterfaceHelper.hitApiBrandWatch(InterfaceHelper.java:695) 
     at com.lsa.akosha.service.brand.BrandCronService.brandSentiments(BrandCronService.java:288) 
     at com.lsa.akosha.util.thread.BrandWatchCronConverse.executeInternal(BrandWatchCronConverse.java:60) 
     at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:113) 
     at org.quartz.core.JobRunShell.run(JobRunShell.java:213) 
     at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:557) 
+0

嘗試調試代碼,也許你會發現你的問題 – 2014-12-02 05:25:58

+0

我已經嘗試過了,但它總是在拋出異常「DataInputStream所輸入=新DataInputStream類(connection.getInputStream());」但是在打印堆棧跟蹤中,它始終會在嘗試讀取時發生異常,例如for循環 – user2531799 2014-12-02 05:31:06

+0

在其他一些機器上嘗試此代碼(或者可能通過轉向反病毒)。 – jsjunkie 2014-12-02 05:38:32

回答

0

我試圖一次又一次地調試它,這次調試時我發現從DataInputStream讀取數據是罪魁禍首。

line dataInputStream.read()每次讀取一個字符,我必須將其轉換爲字符串。下面是代碼

String ret = ""; 
    if(input!=null){ 
     for(int c = input.read(); c != -1; c = input.read()) { //InterfaceHelper.java:695 
      ret = ret + String.valueOf((char)c); 
     } 
    } 

的主要問題是,我將數據讀入int和然後將其轉換成char然後進入字符串即RET =保留+將String.valueOf((char)的C);

現在我已經刪除了DataInputStream並使用了BufferInputStream並使用了直接從InputStream中讀取字符串的bufferInputStream.readLine(),所以沒有類型轉換可以節省大量時間從流中讀取數據,因此直到時間連接和數據流會過期讀取數據,然後關閉兩者。

這樣我的問題就解決了。我張貼我的新代碼,這有助於我解決我的問題。

try{ 
     URL url = new URL("http://example.com/someParams/SOME-ACCESS-TOKEN"); 
     HttpURLConnection connection = (HttpURLConnection)url.openConnection(); 
     connection.setRequestMethod("GET"); 
     connection.setRequestProperty("Content-Type","application/x-www-form-urlencoded"); 
     connection.setRequestProperty("Content-Language", "en-US"); 
     connection.setRequestProperty("X-EXAMPLE-LOGIN", "XXXXXXXX"); 
     connection.setRequestProperty("X-EXAMPLE-PASSWORD", "XXXXXX"); 
     connection.setUseCaches(false); 
     connection.setDoInput(true); 
     connection.setDoOutput(true); 
     connection.setConnectTimeout(99999999); 
     connection.setReadTimeout(99999999); 
     BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream())); 
     //DataInputStream input = new DataInputStream(connection.getInputStream()); 
     String ret = ""; 
     /* if(in!=null){ 
      for(int c = input.read(); c != -1; c = input.read()) { 
       ret = ret + String.valueOf((char)c); 
       if(input==null || connection==null) 
        break; 
      } 
     }*/ 
     String inputLine; 
     while ((inputLine = in.readLine()) != null) 
     { 
      ret = ret + inputLine; 
     } 
     if(in!=null) 
     in.close(); 
     if(connection!=null) 
     connection.disconnect(); 
     if(ret!=null && ret.length()>0){ 
      return ret; 
     } 

    }catch(Exception e) { 
     e.printStackTrace(); 
    } 
+0

不是。這些都不會導致連接重置。 – EJP 2014-12-04 21:07:23

+0

@EJP:我正在從inputstream右邊讀取數據。當我從DataInputStream中讀取數據時,我正在讀取每個字符並轉換爲字符串,這需要花費時間進行類型轉換,但是當我使用bufferReader時,我正在讀取整行,它直接讀取字符串中的數據,不會在內部完成類型轉換或類型轉換,類型轉換。所以它解決了我的問題。 Connection復位的主要原因是我正在讀取已關閉的Stream中的數據,並且close之後的原因是它在從流中讀取數據時的超時 – user2531799 2014-12-05 04:47:17

0

也許它只是怪癖,但我發現在您的文章有些 「奇怪」 的事情。

  1. 您使用SSL連接(因爲它出現在堆棧跟蹤中),但在提供的示例中,根本沒有HTTPS。
  2. application/x-www-form-urlencoded標頭通常與POST請求一起使用。關於此閱讀的完整說明here

我只是說這可能會在某種程度上產生誤導。

現在關於這個問題本身。

全部連接重置意味着由於某種原因客戶端與服務器之間的連接中斷。例如,服務器決定關閉連接。 調試過程中可以很麻煩,在這裏,所以如果我是你,我 會嘗試一對夫婦的技術,根據環境而定你的工作:

  1. 刪除SSL,並與普通的HTTP工作。通過這種方式,您可以放置​​代理,並更好地分析網絡流量。像Burp這樣的東西可以在這裏幫助。

  2. 嘗試消除某些防火牆/代理/任何只是爲了自己的原因轉儲連接的可能性。也許值得在與服務器相同的機器上運行這個代碼(當然如果它是一個可行的選項),只是爲了測試它如何與「localhost」協同工作,你知道的。

  3. 我對這個相當低級的API並不是很熟悉,並且知道它的所有怪癖。 但是也許你可以使用HttpClient來代替,這樣你可能就不需要知道所有的「低級」標誌了,也許它在那裏出錯了。

希望這有助於

0

connection.setRequestMethod( 「GET」);

相反get方法嘗試使用

connection.setRequestMethod( 「POST」);

因爲get方法有限制發送數據。

+0

但是他沒有發送任何數據;並且調用'connection.setDoOutput(true);'將請求方法設置爲' POST'' – EJP 2014-12-02 06:11:28

+0

我正在從服務器讀取數據,我沒有發佈它,所以設置POST不是真正的解決方案 – user2531799 2014-12-02 06:41:12

+0

@ user2531799那麼,爲什麼你正在調用'setRequestMethod()'並設置'「Content-Type」if你不發送任何內容? – EJP 2014-12-02 07:22:17

0

這顯然不是真正的代碼,如我的評論指出以上,但

connection.setRequestProperty("Content-Type","application/x-www-form-urlencoded"); 
connection.setDoOutput(true); 

您沒有發出任何輸出,所以你不應該在所有調用這些方法。和setDoOutput(true)矛盾setRequestMethod("GET");

或者,發送一些輸出。

+0

它因爲我已經刪除了安全憑證代碼... – user2531799 2014-12-02 06:22:53

+0

我對你發佈的代碼發表評論。如果你想對你真實的代碼發表評論,請發佈。刪除安全證書代碼並不能解釋爲什麼你要調用上面列出的兩種方法。我會說你的服務器已經拒絕了你的憑證,但是我們只能猜測你是否遺漏了你的代碼的相關部分。你不需要發佈實際的憑證值,只需要'xxx'和'yyy'就可以了。但是你必須發佈真實的代碼。您甚至沒有發佈HTTPS網址。你在這裏期待很多。 – EJP 2014-12-02 07:20:32

相關問題