因为工作中经常会写点接口类需求,写完HTTP的接口后,就要写测试类来调下服务端的代码。
最近写新的测试调用代码时候,发现项目中new DefaultHttpClient()实例过期很久了,于是查阅了些资料用新版本代码替换了手上项目的代码并且正常测试完、生产上也正常运行完,算是一次补习,特记录下替换过程和调用完后的处理。
1:来看下原来的调用代码,也是最常用的(httpclient版本超过4.2.6):
项目原先用的4.3.1,版本无所谓了,过了4.2.6就已经过时了,过时代码下面我会标注。
HttpClient httpclient = new DefaultHttpClient(); HttpPost httppost = new HttpPost("调用地址"); List<NameValuePair> formparams = new ArrayList<NameValuePair>(); formparams.add(new BasicNameValuePair("参数队列头部", 调用参数)); System.out.println("==== 提交参数 ======" +formparams); UrlEncodedFormEntity uefEntity; try { uefEntity = new UrlEncodedFormEntity(formparams, "UTF-8"); httppost.setEntity(uefEntity); HttpResponse response = httpclient.execute(httppost); HttpEntity entity = response.getEntity(); if(entity!=null){ String results=EntityUtils.toString(entity, "UTF-8"); System.out.println("接口返回值="+results); }
EntityUtils.consume(entity); } catch (ClientProtocolException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e1) { e1.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { // 关闭连接,释放资源 httpclient.getConnectionManager().shutdown(); }
从4.2.6版本后,几乎看到的都是一片过时标识注明,看了maven仓更新时间2013-09-04是4.2.6和4.3同时发布的。
2:下面看下DefaultHttpClient的源码:(追溯源码)
* @since 4.0 * * @deprecated (4.3) use {@link HttpClientBuilder}. */ @ThreadSafe @Deprecated public class DefaultHttpClient extends AbstractHttpClient { /** * Creates a new HTTP client from parameters and a connection manager. * * @param params the parameters * @param conman the connection manager */ public DefaultHttpClient( final ClientConnectionManager conman, final HttpParams params) { super(conman, params); }
看得出来为什么过时了还能用,DefaultHttpClient 继承了 AbstractHttpClient,AbstractHttpClient 继承了CloseableHttpClient。
”Creates a new HTTP client from parameters and a connection manager“ ,创建一个HTTP管理连接的一个”动作“类。
”* @deprecated (4.3) use {@link HttpClientBuilder}.“ ,说明从4.3版本后使用httpclientBuilder新的类,类httpclientBuilder的头部介绍:
”* Please note that some settings used by this class can be mutually exclusive and may not apply when building {@link CloseableHttpClient}“,翻译过来是和CloseableHttpClient有互斥性,看到有hostname,ssl安全证书加载这些就知道是中后期才会运行到的,都是在外部封装类运行提交的参数后内部运行的。
这是调式模式下,图中可以看到参数会传递到httpClientBuilder中处理。
看AbstractHttpClient 继承了CloseableHttpClient的CloseableHttpClient:
@ThreadSafe //线程安全
public abstract class CloseableHttpClient implements HttpClient, Closeable
不难看出实现了httpclient,那么调用方法有了,还实现了关闭流,说明调用完毕后会做关闭处理。CloseableHttpResponse也替换了原来的HttpResponse ,结合资料写下新的调用类:
CloseableHttpClient httpClient = HttpClients.createDefault(); HttpPost httpPost = new HttpPost(”调用地址“); //拼接参数 List<NameValuePair> list = new ArrayList<NameValuePair>(); list.add(new BasicNameValuePair("参数队列头部", 调用参数)); System.out.println("==== 提交参数 ======" +list); CloseableHttpResponse response = null; try { httpPost.setEntity(new UrlEncodedFormEntity(list)); response = httpClient.execute(httpPost); System.out.println("========HttpResponseProxy:========"+response.getStatusLine()); HttpEntity entity = response.getEntity(); if(entity != null){ String result = EntityUtils.toString(entity, "UTF-8"); System.out.println("========接口返回=======" +result); } EntityUtils.consume(entity); //httpClient.getConnectionManager().shutdown(); } catch (Exception e) { e.printStackTrace(); }finally { if(response != null){ try { response.close(); } catch (IOException e) { e.printStackTrace(); } } if(httpClient != null){ try { httpClient.close(); } catch (IOException e) { e.printStackTrace(); } } }
3:旧版本调用完处理和新版本调用完处理:
先看旧版本的关闭方法,
httpclient.getConnectionManager().shutdown();
只要httpclient开启后,BasicClientConnectionManager里的托管连接connManager初始化,其中shutdown开启 = false,运行完调用shutdown方法变 = true。
Response接收httpEntity返回参数时,EntityUtils.consume(entity);关闭参数流操作。
总结:连接动作关闭,接收参数流关闭。
public static void consume(final HttpEntity entity) throws IOException { if (entity == null) { return; } if (entity.isStreaming()) { final InputStream instream = entity.getContent(); if (instream != null) { instream.close(); } } }
新方法调用后关闭方法,
httpClient.close();
新方法是开启了CloseableHttpClient后,PoolingHttpClientConnectionManager赋值CloseableHttpClient 对象并初始化,shutdown为开启状态。
httpClient.getConnectionManager().shutdown(); 和 httpClient.close(); 都是关闭调用功能,因为实现类都impl实现了Closeable关闭流操作,所以在client端调用哪个方法都是可以关闭的,只是有些方法被注明过时了,用新方法不用担心出现@Deprecated标记。
4:总结:
经过几天下来的学习,要知道调用http后,不能只是把client动作关闭就可以的,还需要把response返回参数接收处理完毕后关闭掉。
因为每次调用的不同,不及时关闭在大请求量下就需要谨慎设计代码的安全性了。