<!--http client-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.0.3</version>
</dependency>
<!--http mime,如果需要上传文件的话,必须引用这个包-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.0.3</version>
</dependency>
HttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
HttpResponse response = client.execute(httpGet);
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
String strRtn = EntityUtils.toString(response.getEntity());
}
List<NameValuePair> pairList = new ArrayList<NameValuePair>();
for (String key : params.keySet()) {
pairList.add(new BasicNameValuePair(key, params.get(key)));
}
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(pairList, "utf-8");
HttpPost httpPost = new HttpPost(url);
httpPost.setEntity(entity);
HttpResponse response = client.execute(httpPost);
HttpPost httppost = new HttpPost(url);
FileBody bin = new FileBody(new File(fileName));
StringBody comment = new StringBody("Filename: " + fileName);
MultipartEntity reqEntity = new MultipartEntity();
reqEntity.addPart("bin", bin);
reqEntity.addPart("comment", comment);
httppost.setEntity(reqEntity);
HttpResponse response = httpclient.execute(httppost);
HttpEntity resEntity = response.getEntity();
httpclient中的超时分为connection timeout和socket timeout,从字面意思上理解,前者是建立连接时的超时时间,后者是从socket中读取数据的超时时间。google一番之后,搜到这篇文章:Configuring Timeout with Apache HttpClient 4.0,其中的设置方法如下:
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpParams params = httpClient.getParams();
HttpConnectionParams.setConnectionTimeout(httpParams, connectionTimeoutMillis);
HttpConnectionParams.setSoTimeout(httpParams, socketTimeoutMillis);
这样设置之后超时机制应该起作用了吧,结果实际测试后发现,根本就没什么效果,我特意让程序去连接一个错误的url地址,connection的超时机制完全不起作用。继续google,发现httpclient的超时机制似乎和一般用户的想象中不一样,我的理解是,我设置了超时时间之后,如果超过这个时间还没有处理完,httpclient应该抛出timeout异常了,但是它的超时机制和太多的条件有关联,完全不符合我的直观要求,按照这个帖子httpclient超时的另一种实现方式的描述,我只能新建一个FutureTask,然后通过这个task的接口来实现自己的超时机制,代码如下:
这是一个运行计时任务的代码
/**
* 运行计时任务,在多长时间内超时则返回
*
* @param callable 需要计时的任务
* @param timeout 超时时间
* @param unit 计时单位
* @param <T> 返回值类型
* @return 计时任务的返回值
* @throws ExecutionException
* @throws TimeoutException
* @throws InterruptedException
*/
public static <T> T execTimedCall(Callable<T> callable, Long timeout, TimeUnit unit)
throws ExecutionException, TimeoutException, InterruptedException {
FutureTask<T> task = new FutureTask<T>(callable);
execute(task);
return task.get(timeout, unit);
}
然后在所有需要执行HttpGet和HttpPost的地方这样运行
/**
* 执行http方法,并自动对执行时间进行计时,在超时的情况下抛出异常,防止在UI界面等待太长时间无响应
*
* @param request HttpGet 或 HttpPost
* @return HttpResponse
* @throws WhnkException
*/
private HttpResponse executeTimedHttpMethod(final HttpUriRequest request) throws WhnkException {
HttpResponse response = null;
try {
response = ThreadPool.execTimedCall(new Callable<HttpResponse>() {
@Override
public HttpResponse call() throws Exception {
return client.execute(request);
}
}, REQUEST_TIMEOUT, TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
TerminalApp.getInstance().showLoginErrorDialog();
throw new WhnkException("连接年卡平台超时");
} catch (Exception e) {
if (e instanceof IOException) {
TerminalApp.getInstance().showLoginErrorDialog();
throw new WhnkException("连接年卡平台失败");
}
}
return response;
}
使用ThreadSafeClientConnManager来新建httpclient时,默认会启用连接池,但在网络情况不好的情况下,使用连接池就没什么必要,因为完全不能确定之前的connection是否还能用,最好还是每次都重新新建一个连接,可以在每次http请求之前关闭所有的connection:
client.getConnectionManager().closeIdleConnections(500L, TimeUnit.MILLISECONDS);
client.getConnectionManager().closeExpiredConnections();
上面的代码主要是用在一个用JavaFx写的application上的,这个程序运行在触摸屏电脑上(类似银行门口的取号机),通过3G网卡上网,网络环境不好,httpclient长时间无响应,UI界面会卡住很长时间,加了上面的超时机制之后,可以防止因为网络不好,造成httpclient长时间卡住的问题。
重新打包放到服务器上,之前在程序里加入了自动更新的功能,自动下载最新版本的jar包并重启应用,但在某台终端上测试的时发现,重启应用程序后,日志现在下载失败,服务器返回504错误,google之后发现是WEB服务端超时,应该是nginx的设置问题,具体原因应该是网络慢,在下载jar时超时了,把nginx的设置改一下,在nginx的配置文件中对应的server节点中,加入
send_timeout 60;