2

我正在尝试使用一些外部 API 来获取一些数据。当数据量很小时,一切正常,但是当 API 返回的数据量很大时,我得到CONNECTION RESET异常。下面的代码来自java类InterfaceHelper,我还在我得到异常的第no行标记了注释[尝试从InputStream读取数据时]。

我试图在 STACKOVERFLOW 本身上搜索这么多问题,但没有找到合适的答案。所以请不要将其标记为重复问题。我想知道这个问题背后的原因是什么,以及这个问题的正确解决方案是什么。如果您发现此问题重复,请在将其标记为重复之前回答。我赌你。

在下面找到我使用过的代码。URL 是一些虚拟 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)
4

4 回答 4

1

也许这只是怪癖,但我在你的帖子中发现了一些“奇怪”的东西。

  1. 您使用 SSL 连接(如堆栈跟踪中所示),但在提供的示例中,这根本不是 HTTPS。
  2. application/x-www-form-urlencoded 标头通常与 POST 请求一起使用。阅读这里的完整解释

我只是说这在某种程度上可能会产生误导。

现在关于问题本身。

总而言之-连接重置意味着由于某种原因客户端和服务器之间的连接中断。例如,服务器决定关闭连接。调试过程在这里可能非常棘手,所以如果我是你,我会尝试几种技术,具体取决于你正在处理的环境:

  1. 删除 SSL 并使用纯 HTTP。这样,您可以在中间放置代理并更好地分析网络流量。像Burp这样的东西可以在这里提供帮助。

  2. 尝试消除某些防火墙/代理/任何出于自身原因而转储连接的可能性。也许值得在与服务器相同的机器上运行这段代码(当然,如果它是一个可行的选择)只是为了测试它如何与“localhost”一起工作,你知道的。

  3. 我对这个相当低级的 API 并不熟悉,并且知道它的所有怪癖。但也许你可以使用 HttpClient 代替,这样你可能会消除了解所有“低级”标志的需要,也许那里有问题。

希望这可以帮助

于 2014-12-02T05:48:11.187 回答
0

connection.setRequestMethod("GET");

而是尝试使用 get 方法

connection.setRequestMethod("POST");

因为 get 方法有发送数据的限制。

于 2014-12-02T06:08:15.947 回答
0

正如我在上面的评论中所指出的,这显然不是真正的代码,但是

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

您没有发送任何输出,因此您根本不应该调用这些方法。并且setDoOutput(true)自相矛盾setRequestMethod("GET");

或者,发送一些输出。

于 2014-12-02T06:12:46.077 回答
0

我试图一次又一次地调试它,这次在调试时我发现从 DataInputStream 读取数据是这里的罪魁祸首。

行 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 然后转换为 String 即ret = ret + String.valueOf((char)c); .

现在我已经删除了 DataInputStream 并使用了 BufferInputStream 并使用了 bufferInputStream.readLine() ,它直接从 InputStream 中读取字符串中的行,因此没有类型转换可以节省大量从流中读取数据的时间,因此直到连接和流过期它才会读取数据,然后我关闭两者。

这样我的问题就解决了。我正在发布我的新代码,它可以帮助我解决我的问题。

   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();
   }
于 2014-12-02T06:39:03.043 回答