轻松把玩HttpClient之封装HttpClient工具类(现有网上分享中的最强大的工具类)

Posted 龙轩

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了轻松把玩HttpClient之封装HttpClient工具类(现有网上分享中的最强大的工具类)相关的知识,希望对你有一定的参考价值。

       搜了一下网络上别人封装的HttpClient,大部分特别简单,有一些看起来比较高级,但是用起来都不怎么好用。调用关系不清楚,结构有点混乱。所以也就萌生了自己封装HttpClient工具类的想法。要做就做最好的,本工具类支持插件式配置Header、插件式配置httpclient对象,这样就可以方便地自定义header信息、配置ssl、配置proxy等。


       是不是觉得说的有点悬乎了,那就先看看调用吧:

	public static void testSimple() throws HttpProcessException
		String url = "http://www.oschina.net";
		//简单调用
		String resp = HttpClientUtil.send(url);
		System.out.println("请求结果内容长度:"+ resp.length());
	
	
	public static void testOne() throws HttpProcessException		
		String url = "https://sso.tgb.com:8443/cas/login";
		
		//自定义HttpClient,设置超时、代理、ssl
		//HttpClient client= HCB.custom().timeout(10000).proxy("127.0.0.1", 8087).ssl().build();//采用默认方式(绕过证书验证)
		HttpClient client= HCB.custom().timeout(10000).ssl("D:\\\\keys\\\\wsriakey","tomcat").build();
		
		//设置header信息
		Header[] headers=HttpHeader.custom().keepAlive("false").connection("close").contentType(Headers.APP_FORM_URLENCODED).build();
		
		//执行请求
		String resp=HttpClientUtil.send(client, url, headers);
		System.out.println("请求结果如下:");
		System.out.println(resp);
	

       轻松配置了代理、自定义证书的ssl、以及各种header头信息,是不是觉得还凑合呢,那就继续看吧。


       写这个工具类时,抽象了一下所有的demo,最后封装了一个最基本的方法(拆分成了2个方法了),其所有参数列表有:HttpClient对象、url(必须有)、请求方式、请求参数parasMap、header数组、编码格式encoding。


       由于封装的是工具类,所以最好是无状态的,可以支持多线程的方式调用的,所以方法都是static类型的。这也是为什么要把HttpClient对象也是作为了一个参数传入而非成员变量了,而且这样也为扩展HttpClient的配置提供了便利。


       因为HTTP1.1规范中定义了6种HTTP方法:GET, HEAD, POST, PUT, DELETE, TRACE 和 OPTIONS,其实还有一个PATCH,这几个方法在HttpClient中都有一个对应的类:HttpGet,HttpHead,HttpPost,HttpPut,HttpDelete,HttpTrace、HttpOptions以及HttpPatch。所有的这些类均继承了HttpRequestBase超类,故可以作为参数使用(用枚举类作为参数,用另一个方法来创建具体的请求方法对象)。


       Header头信息也是作为一个重要的参数,在请求特定网站的时候需要设置不同的Header,而header又是比较繁杂的,所以这里也是作为了一个参数传入的,也是方便扩展。


       使用map来作为post方式传入参数是习惯使然,不做过多的解释。


       编码这个参数主要是为了为待提交的数据和反馈结果进行转码处理。


       简单说一下流程:

    1. 创建请求对象request;
    2. 为request设置header信息;
    3. 判断当前请求对象是否是HttpEntityEnclosingRequestBase的子类,如果是,则支持setEntity方法,来设置参数。
    4. 执行请求,并拿到结果(同步阻塞);
    5. 获取并解码请求结果实体;
    6. 关闭链接

       就是这么简单,具体来看看代码吧:

	/**
	 * 请求资源或服务,自定义client对象,传入请求参数,设置内容类型,并指定参数和返回数据的编码
	 * 
	 * @param client		client对象
	 * @param url			资源地址
	 * @param httpMethod	请求方法
	 * @param parasMap		请求参数
	 * @param headers		请求头信息
	 * @param encoding		编码
	 * @return				返回处理结果
	 * @throws HttpProcessException 
	 */
	public static String send(HttpClient client, String url, HttpMethods httpMethod, Map<String,String>parasMap, 
				Header[] headers, String encoding) throws HttpProcessException 
		String body = "";
		try 
			//创建请求对象
			HttpRequestBase request = getRequest(url, httpMethod);
			
			//设置header信息
			request.setHeaders(headers);
			
			//判断是否支持设置entity(仅HttpPost、HttpPut、HttpPatch支持)
			if(HttpEntityEnclosingRequestBase.class.isAssignableFrom(request.getClass()))
				List<NameValuePair> nvps = new ArrayList<NameValuePair>();
				
				//检测url中是否存在参数
				url = Utils.checkHasParas(url, nvps);
				
				//装填参数
				Utils.map2List(nvps, parasMap);
				
				//设置参数到请求对象中
				((HttpEntityEnclosingRequestBase)request).setEntity(new UrlEncodedFormEntity(nvps, encoding));
				
				logger.debug("请求地址:"+url);
				if(nvps.size()>0)
					logger.debug("请求参数:"+nvps.toString());
				
			else
				int idx = url.indexOf("?");
				logger.debug("请求地址:"+url.substring(0, (idx>0 ? idx-1:url.length()-1)));
				if(idx>0)
					logger.debug("请求参数:"+url.substring(idx+1));
				
			
			
			//调用发送请求
			body = execute(client, request, url, encoding);
			
		 catch (UnsupportedEncodingException e) 
			throw new HttpProcessException(e);
		
		return body;
	
		
	
	/**
	 * 请求资源或服务
	 * 
	 * @param client		client对象
	 * @param request		请求对象
	 * @param url			资源地址
	 * @param parasMap		请求参数
	 * @param encoding		编码
	 * @return				返回处理结果
	 * @throws HttpProcessException 
	 */
	private static String execute(HttpClient client, HttpRequestBase request,String url, String encoding) throws HttpProcessException 
		String body = "";
		HttpResponse response =null;
		try 
			
			//执行请求操作,并拿到结果(同步阻塞)
			response = client.execute(request);
			
			//获取结果实体
			HttpEntity entity = response.getEntity();
			
			if (entity != null) 
				//按指定编码转换结果实体为String类型
				body = EntityUtils.toString(entity, encoding);
				logger.debug(body);
			
			EntityUtils.consume(entity);
		 catch (ParseException | IOException e) 
			throw new HttpProcessException(e);
		 finally 
			close(response);
		
		
		return body;
	

       第一个方法中,我们看到有HttpMethods类型的参数,在创建request对象时,用到了它。它是什么呢?其实只是一个枚举类:

	/**
	 * 枚举HttpMethods方法
	 * 
	 * @author arron
	 * @date 2015年11月17日 下午4:45:59 
	 * @version 1.0
	 */
	public enum HttpMethods
		
		/**
		 * 求获取Request-URI所标识的资源
		 */
		GET(0, "GET"), 
		
		/**
		 * 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。
		 * POST请求可能会导致新的资源的建立和/或已有资源的修改
		 */
		POST(1, "POST"),
		
		/**
		 * 向服务器索要与GET请求相一致的响应,只不过响应体将不会被返回。
		 * 这一方法可以在不必传输整个响应内容的情况下,就可以获取包含在响应消息头中的元信息
		 * 只获取响应信息报头
		 */
		HEAD(2, "HEAD"),
		
		/**
		 * 向指定资源位置上传其最新内容(全部更新,操作幂等)
		 */
		PUT	(3, "PUT"), 
		
		/**
		 * 请求服务器删除Request-URI所标识的资源
		 */
		DELETE	(4, "DELETE"), 
		
		/**
		 * 请求服务器回送收到的请求信息,主要用于测试或诊断
		 */
		TRACE(5, "TRACE"), 
		
		/**
		 * 向指定资源位置上传其最新内容(部分更新,非幂等)
		 */
		PATCH	(6, "PATCH"),
		
		/**
		 * 返回服务器针对特定资源所支持的HTTP请求方法。
		 * 也可以利用向Web服务器发送'*'的请求来测试服务器的功能性
		 */
		OPTIONS	(7, "OPTIONS"), 
		
//		/**
//		 * HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器
//		 */
//		CONNECT(99, "CONNECT"),
		;
		
		private int code;
		private String name;
		
		private HttpMethods(int code, String name)
			this.code = code;
			this.name = name;
		
		public String getName() 
			return name;
		
		public int getCode() 
			return code;
		
	

通过getRequest方法,来实例化对应方法的请求对象。

	/**
	 * 根据请求方法名,获取request对象
	 * 
	 * @param url					资源地址
	 * @param method			请求方式
	 * @return
	 */
	private static HttpRequestBase getRequest(String url, HttpMethods method) 
		HttpRequestBase request = null;
		switch (method.getCode()) 
			case 0:// HttpGet
				request = new HttpGet(url);
				break;
			case 1:// HttpPost
				request = new HttpPost(url);
				break;
			case 2:// HttpHead
				request = new HttpHead(url);
				break;
			case 3:// HttpPut
				request = new HttpPut(url);
				break;
			case 4:// HttpDelete
				request = new HttpDelete(url);
				break;
			case 5:// HttpTrace
				request = new HttpTrace(url);
				break;
			case 6:// HttpPatch
				request = new HttpPatch(url);
				break;
			case 7:// HttpOptions
				request = new HttpOptions(url);
				break;
			default:
				request = new HttpPost(url);
				break;
		
		return request;
	

当然最后的关闭链接也是一个小方法:

	/**
	 * 尝试关闭response
	 * 
	 * @param resp				HttpResponse对象
	 */
	private static void close(HttpResponse resp) 
		try 
			if(resp == null) return;
			//如果CloseableHttpResponse 是resp的父类,则支持关闭
			if(CloseableHttpResponse.class.isAssignableFrom(resp.getClass()))
				((CloseableHttpResponse)resp).close();
			
		 catch (IOException e) 
			logger.error(e);
		
	

       当然各种参数的组合方法也简单提供一下(为了节约空间,已去掉注释):

	public static String send(String url) throws HttpProcessException 
		return send(url, Charset.defaultCharset().name());
	
	public static String send(String url, String encoding) throws HttpProcessException 
		return send(url, new Header[],encoding);
	
	public static String send(String url, Header[] headers) throws HttpProcessException 
		return send(url, headers, Charset.defaultCharset().name());
	
	public static String send(String url, Header[] headers, String encoding) throws HttpProcessException 
		return send(url, new HashMap<String,String>(), headers, encoding);
	
	public static String send(String url, Map<String,String>parasMap) throws HttpProcessException 
		return send(url, parasMap, Charset.defaultCharset().name());
	
	public static String send(String url, Map<String,String>parasMap, String encoding) throws HttpProcessException 
		return send(url, parasMap, new Header[], encoding);
	
	public static String send(String url, Map<String,String>parasMap, Header[] headers) throws HttpProcessException 
		return send(url, parasMap, headers, Charset.defaultCharset().name());
	
	public static String send(String url, Map<String,String>parasMap, Header[] headers, String encoding) throws HttpProcessException 
		return send(url, HttpMethods.POST, parasMap, headers, encoding);
		
	public static String send(String url, HttpMethods httpMethod) throws HttpProcessException 
		return send(url, httpMethod, Charset.defaultCharset().name());
	
	public static String send(String url, HttpMethods httpMethod, String encoding) throws HttpProcessException 
		return send(url, httpMethod, new Header[],encoding);
	
	public static String send(String url, HttpMethods httpMethod, Header[] headers) throws HttpProcessException 
		return send(url, httpMethod, headers, Charset.defaultCharset().name());
	
	public static String send(String url, HttpMethods httpMethod, Header[] headers, String encoding) throws HttpProcessException 
		return send(url, httpMethod, new HashMap<String, String>(), headers, encoding);
	
	public static String send(String url, HttpMethods httpMethod, Map<String,String>parasMap) throws HttpProcessException 
		return send(url, httpMethod, parasMap, Charset.defaultCharset().name());
	
	public static String send(String url, HttpMethods httpMethod, Map<String,String>parasMap, String encoding) throws HttpProcessException 
		return send(url, httpMethod, parasMap, new Header[], encoding);
	
	public static String send(String url, HttpMethods httpMethod, Map<String,String>parasMap, Header[] headers) throws HttpProcessException 
		return send(url, httpMethod, parasMap, headers, Charset.defaultCharset().name());
		
	public static String send(String url, HttpMethods httpMethod, Map<String,String>parasMap, Header[] headers, String encoding) throws HttpProcessException 
		return send(create(url), url, httpMethod, parasMap, headers, encoding);
	
	
	public static String send(HttpClient client, String url) throws HttpProcessException 
		return send(client, url, Charset.defaultCharset().name());
	
	public static String send(HttpClient client, String url, String encoding) throws HttpProcessException 
		return send(client, url, new Header[], encoding);
	
	public static String send(HttpClient client, String url, Header[] headers) throws HttpProcessException 
		return send(client, url, headers, Charset.defaultCharset().name());
	
	public static String send(HttpClient client, String url, Header[] headers, String encoding) throws HttpProcessException 
		return send(client, url, new HashMap<String, String>(), headers, encoding);
	
	public static String send(HttpClient client, String url, Map<String,String>parasMap) throws HttpProcessException 
		return send(client, url, parasMap, Charset.defaultCharset().name());
	
	public static String send(HttpClient client, String url, Map<String,String>parasMap, String encoding) throws HttpProcessException 
		return send(client, url, parasMap, new Header[], encoding);
	
	public static String send(HttpClient client, String url, Map<String,String>parasMap, Header[] headers) throws HttpProcessException 
		return send(client, url, parasMap, headers, Charset.defaultCharset().name());
	
	public static String send(HttpClient client, String url, Map<String,String>parasMap,Header[] headers,String encoding) throws HttpProcessException 
		return send(client, url, HttpMethods.POST, parasMap, headers, encoding);
	
	public static String send(HttpClient client, String url, HttpMethods httpMethod) throws HttpProcessException 
		return send(client, url, httpMethod, Charset.defaultCharset().name());
	
	public static String send(HttpClient client, String url, HttpMethods httpMethod, String encoding) throws HttpProcessException 
		return send(client, url, httpMethod, new Header[], encoding);
	
	public static String send(HttpClient client, String url, HttpMethods httpMethod, Header[] headers) throws HttpProcessException 
		return send(client, url, httpMethod, headers, Charset.defaultCharset().name());
	
	public static String send(HttpClient client, String url, HttpMethods httpMethod, Header[] headers, String encoding) throws HttpProcessException 
		return send(client, url, httpMethod, new HashMap<String, String>(), headers, encoding);
	
	public static String send(HttpClient client, String url, HttpMethods httpMethod, Map<String,String>parasMap) throws HttpProcessException 
		return send(client, url, httpMethod, parasMap, Charset.defaultCharset().name());
	
	public static String send(HttpClient client, String url, HttpMethods httpMethod, Map<String,String>parasMap, String encoding) throws HttpProcessException 
		return send(client, url, httpMethod, parasMap, new Header[], encoding);
	
	public static String send(HttpClient client, String url, HttpMethods httpMethod, Map<String,String>parasMap, Header[] headers) throws HttpProcessException 
		return send(client, url, httpMethod, parasMap, headers, Charset.defaultCharset().name());
	

       可以看到上面这一堆方法,其实主要分成2类,一类是传入client对象的,一组是没有传入的。也就是说该工具类提供了一种默认的client对象。这个将会在下一篇文章会有补充。


       当然,为了方便操作,还是提供了get、post、put、patch、delete、head、options、trace等方法,由于推荐使用send方法,所以这几个方法只是做了一个简单的调用:

	public static String get(String url, Header[] headers,String encoding) throws HttpProcessException 
		return get(create(url), url, headers, encoding);
		
	public static String get(HttpClient client, String url, Header[] headers,String encoding) throws HttpProcessException 
		return send(client, url, HttpMethods.GET, headers, encoding);
	
	
	public static String post(String url, Map<String,String>parasMap,Header[] headers,String encoding) throws HttpProcessException 
		return post(create(url), url, parasMap, headers, encoding);
	
	public static String post(HttpClient client, String url, Map<String,String>parasMap,Header[] headers,String encoding) throws HttpProcessException 
		return send(client, url, HttpMethods.POST, parasMap, headers, encoding);
	
	
	public static String put(String url, Map<String,String>parasMap,Header[] headers,String encoding) throws HttpProcessException 
		return put(create(url), url, parasMap, headers, encoding);
	
	public static String put(HttpClient client, String url, Map<String,String>parasMap,Header[] headers,String encoding) throws HttpProcessException 
		return send(client, url, HttpMethods.PUT, parasMap, headers, encoding);
	
	
	public static String delete(String url, Header[] headers,String encoding) throws HttpProcessException 
		return delete(create(url), url, headers, encoding);
	
	public static String delete(HttpClient client, String url, Header[] headers,String encoding) throws HttpProcessException 
		return send(client, url, HttpMethods.DELETE, headers, encoding);
	
	
	public static String patch(String url, Map<String,String>parasMap,Header[] headers,String encoding) throws HttpProcessException 
		return patch(create(url), url, parasMap, headers, encoding);
	
	public static String patch(HttpClient client, String url, Map<String,String>parasMap, Header[] headers,String encoding) throws HttpProcessException 
		return send(client, url, HttpMethods.PATCH, parasMap, headers, encoding);
	
	
	public static String head(String url, Header[] headers,String encoding) throws HttpProcessException 
		return head(create(url), url, headers, encoding);
	
	public static String head(HttpClient client, String url, Header[] headers,String encoding) throws HttpProcessException 
		return send(client, url, HttpMethods.HEAD, headers, encoding);
	
	
	public static String options(String url, Header[] headers,String encoding) throws HttpProcessException 
		return options(create(url), url, headers, encoding);
	
	public static String options(HttpClient client, String url, Header[] headers,String encoding) throws HttpProcessException 
		return send(client, url, HttpMethods.OPTIONS, headers, encoding);
	
	
	public static String trace(String url, Header[] headers,String encoding) throws HttpProcessException 
		return trace(create(url), url, headers, encoding);
	
	public static String trace(HttpClient client, String url, Header[] headers,String encoding) throws HttpProcessException 
		return send(client, url, HttpMethods.TRACE, headers, encoding);
	

       差点忘记了,最后还有一个简单的通用工具类

/** 
 * 
 * @author arron
 * @date 2015年11月10日 下午12:49:26 
 * @version 1.0 
 */
public class Utils 

	/**
	 * 检测url是否含有参数,如果有,则把参数加到参数列表中
	 * 
	 * @param url					资源地址
	 * @param nvps				参数列表
	 * @return	返回去掉参数的url
	 */
	public static String checkHasParas(String url, List<NameValuePair> nvps) 
		// 检测url中是否存在参数
		if (url.contains("?") && url.indexOf("?") < url.indexOf("=")) 
			Map<String, String> map = buildParas(url.substring(url
					.indexOf("?") + 1));
			map2List(nvps, map);
			url = url.substring(0, url.indexOf("?"));
		
		return url;
	

	/**
	 * 参数转换,将map中的参数,转到参数列表中
	 * 
	 * @param nvps				参数列表
	 * @param map				参数列表(map)
	 */
	public static void map2List(List<NameValuePair> nvps, Map<String, String> map) 
		if(map==null) return;
		// 拼接参数
		for (Entry<String, String> entry : map.entrySet()) 
			nvps.add(new BasicNameValuePair(entry.getKey(), entry
					.getValue()));
		
	
	
	
	/**
	 * 生成参数
	 * 参数格式“k1=v1&k2=v2”
	 * 
	 * @param paras				参数列表
	 * @return						返回参数列表(map)
	 */
	public static Map<String,String> buildParas(String paras)
		String[] p = paras.split("&");
		String[][] ps = new String[p.length][2];
		int pos = 0;
		for (int i = 0; i < p.length; i++) 
			pos = p[i].indexOf("=");
			ps[i][0]=p[i].substring(0,pos);
			ps[i][1]=p[i].substring(pos+1);
			pos = 0;
		
		return buildParas(ps);
	
	
	/**
	 * 生成参数
	 * 参数类型:"k1","v1","k2","v2"
	 * 
	 * @param paras 				参数列表
	 * @return						返回参数列表(map)
	 */
	public static Map<String,String> buildParas(String[][] paras)
		// 创建参数队列    
		Map<String,String> map = new HashMap<String, String>();
		for (String[] para: paras) 
			map.put(para[0], para[1]);
		
		return map;
	
	

       简单的封装就是这样了。


       由于HttpClient和Header都作为参数传入,所以也可以进行扩展,比如代理、ssl等都是对HttpClient进行配置的,下面的文章就分别分享一下如何插件式配置HttpClient以及Header。敬请期待。

       代码已上传https://github.com/Arronlong/httpclientUtil

       httpclientUtil (QQ交流群:548452686 

以上是关于轻松把玩HttpClient之封装HttpClient工具类(现有网上分享中的最强大的工具类)的主要内容,如果未能解决你的问题,请参考以下文章

轻松把玩HttpClient之封装HttpClient工具类,封装输入参数,简化工具类

轻松把玩HttpClient之封装HttpClient工具类,插件式配置Header

轻松把玩HttpClient之封装HttpClient工具类,携带Cookie的请求

轻松把玩HttpClient之封装HttpClient工具类,单线程调用及多线程批量调用测试

轻松把玩HttpClient之封装HttpClient工具类,新增验证码识别功能

轻松把玩HttpClient之封装HttpClient工具类,优化启用Http连接池策略