http client使用

maven引用


<!--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>

get方法


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());
}

POST

            
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);

POST上传文件


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;
}

关闭connection pool

使用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;

你可能感兴趣的:(java,httpclient)