我正在尝试使用以下代码向我的服务器发送请求。总是在第3次请求时失败。
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
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.CoreConnectionPNames;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
public class HttpClientTest {
private HttpClient client;
public HttpClientTest() {
HttpParams params = new BasicHttpParams();
params.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 15000);
params.setParameter(CoreConnectionPNames.SO_TIMEOUT, 15000);
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, "utf-8");
HttpProtocolParams.setUseExpectContinue(params, true);
ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager();
cm.setMaxTotal(100);
client = new DefaultHttpClient(cm, params);
while (true) {
HttpPost mPost = new HttpPost("http://myip/myservice");
JSONObject json = new JSONObject();
try {
json.put("serialNumber", "abcd");
} catch (JSONException e1) {
e1.printStackTrace();
}
StringEntity s = null;
try {
s = new StringEntity(json.toString());
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
s.setContentEncoding("UTF-8");
s.setContentType("application/json");
mPost.setEntity(s);
JSONObject response = null;
System.out.println("HttpClientTest ---> send post");
HttpResponse mHttpResponse;
try {
mHttpResponse = client.execute(mPost);
System.out.println("HttpClientTest ---> get response");
if(mHttpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
HttpEntity entity = mHttpResponse.getEntity();
ContentType contentType = ContentType.getOrDefault(entity);
Charset charset = contentType.getCharset();
response = new JSONObject(new JSONTokener(new InputStreamReader(entity.getContent(), charset)));
System.out.println("HttpClientTest ---> get result:" + response.toString());
} else {
mPost.abort();
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
HttpClientTest t = new HttpClientTest();
}
}
例外如下:
org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection
at org.apache.http.impl.conn.tsccm.ConnPoolByRoute.getEntryBlocking(ConnPoolByRoute.java:417)
at org.apache.http.impl.conn.tsccm.ConnPoolByRoute$1.getPoolEntry(ConnPoolByRoute.java:300)
at org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager$1.getConnection(ThreadSafeClientConnManager.java:224)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:401)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:820)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:754)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:732)
at com.i360r.client.takeaway.network.HttpClientTest.<init>(HttpClientTest.java:68)
at com.i360r.client.takeaway.network.HttpClientTest.main(HttpClientTest.java:88)
答案 0 :(得分:48)
我遇到了同样的问题,我找到了修复程序。
此超时是因为连接泄漏。在我的情况下,我使用httpDelete
方法并且不使用响应。而是检查响应的状态。
修复方法是,需要使用响应实体。为了确保正确释放系统资源,必须关闭与实体关联的内容流。
所以我使用了EntityUtils.consumeQuietly(response.getEntity());
来确保实体内容被完全消耗,内容流(如果存在)被关闭。
答案 1 :(得分:27)
我修好了!在mPost.releaseConnection()
块中添加finally
。
try {
} catch (Exception e) {
} finally {
mPost.releaseConnection();
}
将包org.apache.httpcomponents
更新为4.2.1
答案 2 :(得分:3)
如果你在DropWizard 0.6.2中使用MultiThreadedHttpConnectionManager
,后台创建一个带有默认配置的false
,并且默认配置只允许2个并发http,那么也会发生这种情况一次more info here的连接。
因此,使用此配置,如果您的服务器一直被淹没并向同一主机发出请求,那么您一次只允许运行最多2个连接!
答案 3 :(得分:3)
只需将获取响应的行放入try-with-resources并使用CloseableHttpResponse而不是HttpResponse,如下所示:
try(final CloseableHttpResponse mHttpResponse = client.execute(mPost);)
{
System.out.println("HttpClientTest ---> get response");
....remainder code
mHttpResponse对象将自动消耗并为您关闭
希望这有帮助!
答案 4 :(得分:0)
正如Rama所说,这可能是连接泄漏的迹象。
releaseConnection()
可以帮助解决此问题,但您可能需要找出根本原因。
此外,这可能会发生,因为没有可供租用的可用连接,而当您没有为timeout
配置HttpClient
时,可能会发生这种情况。在这种情况下,releaseConnection()
将无济于事。
答案 5 :(得分:0)
实际上... 完成响应后,只需关闭它,而无需关闭连接。
CloseableHttpResponse response = client.execute(httpPost, context);
...做您需要做的事...
response.close();
答案 6 :(得分:0)
我们遇到了同样的问题,我们受到了限制,因为来自池的连接的DefaultMaxPerRoute初始值为2。我们的API是一个API,它将使用相同的URI触发不同的调用,但正文不同。像这样将其显式设置为更高的值
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setMaxTotal(40);
cm.setDefaultMaxPerRoute(20);
我们能够解决它。
答案 7 :(得分:0)
在我的情况下,使用实体内容流的bufferedReader没有关闭。关闭它可以解决该错误。
答案 8 :(得分:0)
我遇到了同样的错误。原来,我需要关闭响应。
CloseableHttpResponse response = null;
try {
response = ##some code
} catch(Exception e) {
if (response != null) {
response.close();
}
}