简体   繁体   English

HttpClient无法从服务器获取响应

[英]HttpClient can't get response from server

This problem has blocked our whole team half a day! 这个问题已经使我们的整个团队半天无法工作了!

We use apache httpclient 4.3.x to post and get data from an storage server which provides http api. 我们使用apache httpclient 4.3.x来发布并从提供http api的存储服务器中获取数据。 In order to improve performance, we used PoolingHttpClientConnectionManager : 为了提高性能,我们使用了PoolingHttpClientConnectionManager

public HttpClient createHttpClient() {
    Registry registry = RegistryBuilder.create()....build();
    PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
    connectionManager.setMaxTotal(50);
    connectionManager.setDefaultMaxPerRoute(50);

    CloseableHttpClient httpClient = HttpClients.custom()
       .setConnectionManager(connectionManager)
       .build();
    return httpClient;
}

Then we hold an instance of the httpClient in our program, reuse it with every http request: 然后,在程序中保存一个httpClient实例,将其与每个http请求一起重用:

Global httpClient: 全局httpClient:

HttpClient httpClient = createHttpClient();

Post some data: 发布一些数据:

HttpPost httpPut = new HttpPost("...");
HttpResponse response = httpClient.execute(httpPut);

// Notice we get the response content here!
String content = EntityUtils.toString(response.getEntity());
System.out.println(content);

httpPut.releaseConnection();
response.close();

Then get: 然后得到:

HttpGet httpGet = new HttpGet("...");

// Blocked at this line !!!!
HttpResponse response = httpClient.execute(httpGet);

String content = EntityUtils.toString(response.getEntity());
System.out.println(content);

httpPut.releaseConnection();
response.close();    

Please notice the line: // Blocked at this line !!!! 请注意以下行: // Blocked at this line !!!!

The program has blocked at that line and never go to next line. 程序已在该行被阻止,并且从不进入下一行。 In debugging mode, I can see it has been blocked at: 在调试模式下,我可以看到它已在以下位置被阻止:

SocketInputStream.socketRead0()

I've searched for a lot of questions and documents, but no lucky. 我搜索了很多问题和文档,但并不幸运。


My colleage just fix it by setting NoConnectionReuseStrategy.INSTANCE : 我的NoConnectionReuseStrategy.INSTANCE只是通过设置NoConnectionReuseStrategy.INSTANCE解决它:

 HttpClients.custom()
       .setConnectionManager(connectionManager)
       // Following line fixed the problem, but why?
       .setConnectionReuseStrategy(NoConnectionReuseStrategy.INSTANCE)
       .build();

Now it doens't blocked, but why? 现在它没有被阻止,但是为什么呢?

What does "reuse connection" mean? “重用连接”是什么意思? And is there performance issue by using NoConnectionReuseStrategy ? 使用NoConnectionReuseStrategy是否存在性能问题?

Thank you, guys~ 谢谢大家〜

I tried to reproduce the blocking http-get (also as an exercise for myself) but even without closing responses I could not get it to block. 我试图重现阻止的http-get(也是我自己的一种练习),但是即使没有关闭响应,我也无法阻止它。 The ONLY time I managed to make the http-get block is by doing a response.getEntity().getContent() without reading from the returned InputStream and without closing the returned InputStream . 我设法制作http-get块的唯一时间是通过执行response.getEntity().getContent()而不读取返回的InputStream且不关闭返回的InputStream For my tests I used Tomcat 7.0.47 with two very simple servlets (one responding "OK" to a get, the other echoing a post) as a server. 在我的测试中,我将Tomcat 7.0.47与两个非常简单的servlet(作为响应get响应“ OK”,另一个响应POST)用作服务器。 The client started 50 threads with each thread performing 30 alternating http-get and http-post request (total of 1500 requests). 客户端启动了50个线程,每个线程执行30个交替的http-get和http-post请求(总共1500个请求)。 The client did not use the RegistryBuilder , instead the default one is used (created by the PoolingHttpClientConnectionManager itself). 客户端未使用RegistryBuilder ,而是使用默认值(由PoolingHttpClientConnectionManager本身创建)。

About the NoConnectionReuseStrategy : by default (HttpClient created with HttpClients.createDefault() , I used org.apache.httpcomponents:httpclient:4.3.1 ) a connection pool is used with a maximum of 2 connections to 1 server. 关于NoConnectionReuseStrategy :默认情况下(使用HttpClients.createDefault()创建的HttpClients.createDefault() ,我使用的是org.apache.httpcomponents:httpclient:4.3.1 ),连接池最多使用1个服务器的2个连接。 Eg even if 5 threads are doing all kinds of requests at the same time to 1 server, the connection pool opens only 2 connections, re-uses them for all requests and ensures that 1 connection is used by 1 thread at any given time. 例如,即使5个线程同时对1个服务器执行各种请求,连接池也仅打开2个连接,将它们重新用于所有请求,并确保在任何给定时间1个线程使用1个连接。 This can have a very positive impact on client performance and significantly reduces load on the server. 这会对客户端性能产生非常积极的影响,并显着减少服务器上的负载。 The only thing you must make sure is to call response.close() in a finally-block (this ensures the connection is returned to the connection pool). 您唯一必须确保的是在finally块中调用response.close() (这可确保将连接返回到连接池)。 By using the NoConnectionReuseStrategy you basically disable the connection pool: for each request a new connection will be created. 通过使用NoConnectionReuseStrategy您基本上可以禁用连接池:对于每个请求,将创建一个新的连接。 I recommend you enable debug-logging for category org.apache.http.impl.conn.PoolingHttpClientConnectionManager , it is very informative. 我建议您为org.apache.http.impl.conn.PoolingHttpClientConnectionManager类别启用调试日志记录,这非常有用。

A note about httpPut.releaseConnection() : this does not actually release a connection, it only ensures that you can re-use the "httpPut" object in a next request (see the apidocs , follow the shown link). 关于httpPut.releaseConnection()注释:实际上并不会释放连接,它只是确保您可以在下一个请求中重用“ httpPut”对象(请参阅apidocs单击显示的链接)。 Also note that in your code for the "httpGet", you call releaseConnection() on "httpPut" instead of "httpGet". 另请注意,在“ httpGet”的代码中,您在“ httpPut”而不是“ httpGet”上调用releaseConnection()

Ran into this problem just a while back. 不久前就遇到了这个问题。 In case someone else comes across this problem, this post might be useful. 如果其他人遇到此问题,这篇文章可能会有用。

I am using a Java Servlet to service my requests. 我正在使用Java Servlet来处理我的请求。 When I wrote to the response stream using the PrintWriter instance my client blocked. 当我使用PrintWriter实例写入响应流时,客户端被阻止。 Tried writing to the OutputStream directly response.getOutputStream.write("myresponse") and it worked. 尝试直接写入到OutputStream的response.getOutputStream.write("myresponse")并成功。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM