使用HttpClient管理HTTP请求

HTTP请求工具类,基于HttpClient4.5.1实现,可以帮你在程序后台默默完成POST、GET请求,使用方法参见注释,上代码:

HttpHandler httpHandler = new HttpHandler();
try {

	httpHandler.init();

	Map resultMap = httpHandler.doGet("http://www.baidu.com");
	if (CollectionUtil.isNotEmpty(resultMap)) {

		String result = new String((byte[]) resultMap.get(HttpHandler.BODY_KEY));

		System.out.println(result);
	}
} catch (Exception ex) {

	ex.printStackTrace();
} finally {

	httpHandler.destroy();
}

另外有大量的重载方法用于一些特殊场合,参数、Cookie等都可以通过Map动态传递,如需连续请求,连续调用同一对象即可,代码也支持自动跳转。

工具类源码:

/**
 * HttpHandler.java
 * Copyright ® 2012 窦海宁
 * All right reserved
 */

package org.aiyu.core.common.util.net;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.zip.GZIPInputStream;

import org.aiyu.core.common.util.CollectionUtil;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.config.RequestConfig.Builder;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.DefaultRedirectStrategy;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;

/**
 * <p>Http工具类
 * 
 * <p>Http工具类,为系统提供通用Http访问操作方法:
 * <p>
 * <p>1、发送GET请求;
 * <p>2、发送POST请求。
 * 
 * @author  窦海宁, [email protected]
 * @since   AiyuCommonCore-1.0
 * @version AiyuCommonCore-1.0
 */
public class HttpHandler {

	//日志对象
	private static final Logger logger = Logger.getLogger(HttpHandler.class);

	private static final String DEFAULT_CHARSET    = "UTF-8";

	public static final String BODY_KEY            = "body";
	public static final String REDIRECT_BODY_KEY   = "redirect_body";
	public static final String HEADER_KEY          = "header";
	public static final String REDIRECT_HEADER_KEY = "redirect_header";
	public static final String COOKIE_KEY          = "cookie";

	//浏览器Agent
	public static final String USER_AGENT_FIREFOX  = "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko";

	private String                charset       = null; //字符编码,默认为UTF-8
	private String                proxyUrl      = null; //代理服务器地址
	private int                   proxyPort     = 0;    //代理服务器端口号
	private int                   timeout       = 0;    //请求超时时间

	private int                   cookieVersion = 0;
	private String                cookiePath    = null;
	private String                cookieDomain  = null;
	private CookieStore           cookieStore   = null;
	private HttpClientContext     localContext  = null; //本地会话上下文

	private CloseableHttpClient   httpClient    = null;
	private CloseableHttpResponse httpResponse  = null;

	/**
	 * <p>默认构造函数
	 * 
	 * @modify 窦海宁, 2017-01-17
	 */
	public HttpHandler() {

		if (StringUtils.isBlank(this.charset)) {

			this.charset = HttpHandler.DEFAULT_CHARSET;
		}
	}

	/**
	 * <p>初始化访问对象
	 * 
	 * @modify 窦海宁, 2017-01-17
	 */
	public void init() {

		//设置默认的恢复策略,在发生异常时候将自动重试3次,在这里你也可以设置成自定义的恢复策略
		HttpRequestRetryHandler retryHandler = new DefaultHttpRequestRetryHandler();

		//配置超时时间(连接服务端超时1秒,请求数据返回超时2秒)
		RequestConfig requestConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.DEFAULT).build();

		this.cookieStore  = new BasicCookieStore();
		this.localContext = HttpClientContext.create();

		//设置默认跳转以及存储cookie
		this.httpClient   = HttpClientBuilder.create()
							.setRedirectStrategy(new DefaultRedirectStrategy())
							.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy())
							.setRetryHandler(retryHandler).setDefaultRequestConfig(requestConfig).build();

		this.localContext.setCookieStore(this.cookieStore);
	}

	/**
	 * <p>关闭访问对象并释放资源
	 * 
	 * @modify 窦海宁, 2017-01-17
	 */
	public void destroy() {

		if (this.httpClient != null) {

			try {

				this.httpClient.close();
			} catch (Exception ex) {

				ex.printStackTrace();
			}
		}

		System.gc();
	}

	/**
	 * <p>发送GET请求
	 * 
	 * @param  url GET请求地址
	 * 
	 * @return 与当前请求对应的响应内容集合
	 * 
	 * @modify 窦海宁, 2017-01-15
	 */
	public Map doGet(String url) {

		return this.doGet(url , null , null);
	}

	/**
	 * <p>发送GET请求
	 * 
	 * @param  url       GET请求地址
	 * @param  headerMap GET请求头参数容器
	 * @param  charset   参数字符集名称
	 * 
	 * @return 与当前请求对应的响应内容集合
	 * 
	 * @modify 窦海宁, 2017-01-15
	 */
	public Map doGet(String url , Map headerMap) {

		return this.doGet(url , null , null , headerMap);
	}

	/**
	 * <p>发送GET请求
	 * 
	 * @param  url       GET请求地址
	 * @param  cookieMap POST请求Cookie参数容器
	 * @param  headerMap GET请求头参数容器
	 * 
	 * @return 与当前请求对应的响应内容集合
	 * 
	 * @modify 窦海宁, 2017-01-15
	 */
	public Map doGet(String url , Map cookieMap , Map headerMap) {

		return this.doGet(url , null , cookieMap , headerMap);
	}

	/**
	 * <p>发送GET请求
	 * 
	 * @param  url            GET请求地址
	 * @param  queryStringMap 查询字符串参数容器
	 * @param  cookieMap      POST请求Cookie参数容器
	 * @param  headerMap      GET请求头参数容器
	 * 
	 * @return 与当前请求对应的响应内容容器,包括响应头、响应主体,可通过本类提供的静态常量作为键值提取
	 * 
	 * @modify 窦海宁, 2017-01-15
	 */
	public Map doGet(String url , Map queryStringMap , Map cookieMap , Map headerMap) {

		Map resultMap = null;

		try {

			HttpGet httpGet       = new HttpGet(this.createUrl(url , queryStringMap));
			Builder configBuilder = RequestConfig.custom();

			//设置请求超时时间(毫秒)
			if (this.timeout > 0) {

				configBuilder.setSocketTimeout(this.timeout);
				configBuilder.setConnectTimeout(this.timeout);
				configBuilder.setConnectionRequestTimeout(this.timeout);
			}

			//设置代理
			if (StringUtils.isNotBlank(this.proxyUrl)) {

				HttpHost proxy = new HttpHost(this.proxyUrl , this.proxyPort);

				configBuilder.setProxy(proxy);
			}

			//设置默认Cookie环境
			if (StringUtils.isBlank(this.cookiePath)) {

				this.cookiePath = httpGet.getURI().getPath();
			}
			if (StringUtils.isBlank(this.cookieDomain)) {

				this.cookieDomain = httpGet.getURI().getHost();
			}

			//设置请求策略
			httpGet.setConfig(configBuilder.build());

			//设置请求头
			this.addHeader(headerMap , httpGet);
			//设置请求Cookie
			this.addCookie(cookieMap);

			this.httpResponse = this.httpClient.execute(httpGet , this.localContext);
			if (this.httpResponse.getStatusLine().getStatusCode() == 200) {

				resultMap = new HashMap();

				//读取头内容
				Map      responseHeaderMap = new HashMap();
				Header[] headerArray       = this.httpResponse.getAllHeaders();
				for (int i = 0 ; i < headerArray.length ; i++) {

					responseHeaderMap.put(headerArray[i].getName() , headerArray[i].getValue());
				}
				resultMap.put(HttpHandler.HEADER_KEY , responseHeaderMap);

				//读取内容
				resultMap.put(HttpHandler.BODY_KEY , this.getBody(this.httpResponse));
			} else {

				System.err.println("Method failed: " + this.httpResponse.getStatusLine());
			}

			EntityUtils.consume(this.httpResponse.getEntity());

			this.initCookieEnvironment();
		} catch (Exception ex) {

			ex.printStackTrace();
		} finally {

			this.closeHttpResponse();
		}

		return resultMap;
	}

	/**
	 * <p>发送POST请求(如返回跳转指令,该方法会自动以GET方式跳转)
	 * 
	 * @param  url   POST请求地址
	 * @param  param 请求参数实体对象
	 * 
	 * @return 与当前请求对应的响应内容字节数组
	 * 
	 * @modify 窦海宁, 2017-01-15
	 */
	public Map doPost(String url , Object param) {

		return this.doPost(url , null , null , null , param);
	}

	/**
	 * <p>发送POST请求(如返回跳转指令,该方法会自动以GET方式跳转)
	 * 
	 * @param  url       POST请求地址
	 * @param  headerMap POST请求头参数容器
	 * @param  param     请求参数实体对象
	 * 
	 * @return 与当前请求对应的响应内容字节数组
	 * 
	 * @modify 窦海宁, 2017-01-15
	 */
	public Map doPost(String url , Map headerMap , Object param) {

		return this.doPost(url , null , null , headerMap , param);
	}

	/**
	 * <p>发送POST请求(如返回跳转指令,该方法会自动以GET方式跳转)
	 * 
	 * @param  url            POST请求地址
	 * @param  queryStringMap 查询字符串参数容器
	 * @param  headerMap      POST请求头参数容器
	 * @param  param          请求参数实体对象
	 * 
	 * @return 与当前请求对应的响应内容容器,包括响应头、响应主体,可通过本类提供的静态常量作为键值提取
	 * 
	 * @modify 窦海宁, 2017-01-15
	 */
	public Map doPost(String url , Map queryStringMap , Map headerMap , Object param) {

		return this.doPost(url , queryStringMap , null , headerMap , param);
	}

	/**
	 * <p>发送POST请求(如返回跳转指令,该方法会自动以GET方式跳转)
	 * 
	 * @param  url            POST请求地址
	 * @param  queryStringMap 查询字符串参数容器
	 * @param  cookieMap      POST请求Cookie参数容器
	 * @param  headerMap      POST请求头参数容器
	 * @param  param          请求参数实体对象
	 * 
	 * @return 与当前请求对应的响应内容容器,包括响应头、响应主体,可通过本类提供的静态常量作为键值提取
	 * 
	 * @modify 窦海宁, 2017-01-15
	 */
	public Map doPost(String url , Map queryStringMap , Map cookieMap , Map headerMap , Object param) {

		Map    resultMap   = null;
		String redirectUrl = null;

		try {

			HttpPost httpPost      = new HttpPost(this.createUrl(url , queryStringMap));
			Builder  configBuilder = RequestConfig.custom();

			//设置请求超时时间(毫秒)
			if (this.timeout > 0) {

				configBuilder.setSocketTimeout(this.timeout);
				configBuilder.setConnectTimeout(this.timeout);
				configBuilder.setConnectionRequestTimeout(this.timeout);
			}

			//设置代理
			if (StringUtils.isNotBlank(this.proxyUrl)) {

				HttpHost proxy = new HttpHost(this.proxyUrl , this.proxyPort);

				configBuilder.setProxy(proxy);
			}

			//设置默认Cookie环境
			this.cookiePath   = httpPost.getURI().getPath();
			this.cookieDomain = httpPost.getURI().getHost();

			//设置请求策略
			httpPost.setConfig(configBuilder.build());

			//设置请求头
			this.addHeader(headerMap , httpPost);
			//设置请求Cookie
			this.addCookie(cookieMap);
			//设置请求参数
			HttpEntity postEntity = this.addParam(param , httpPost);

			httpPost.setEntity(postEntity);

			this.httpResponse = this.httpClient.execute(httpPost , this.localContext);

			switch (this.httpResponse.getStatusLine().getStatusCode())
			{
			case 301 :
			case 302 :
			case 304 :

				redirectUrl = this.httpResponse.getFirstHeader("Location").getValue();

			case 200 :
			case 500 :

				resultMap = new HashMap();

				//读取头内容
				Map      responseHeaderMap = new HashMap();
				Header[] headerArray       = httpPost.getAllHeaders();
				for (int i = 0 ; i < headerArray.length ; i++) {

					responseHeaderMap.put(headerArray[i].getName() , headerArray[i].getValue());
				}
				resultMap.put(HttpHandler.HEADER_KEY , responseHeaderMap);

				//读取内容
				resultMap.put(HttpHandler.BODY_KEY , this.getBody(this.httpResponse));

				break;

			default :

				System.err.println("Method failed: " + this.httpResponse.getStatusLine());
			}

			EntityUtils.consume(this.httpResponse.getEntity());
		} catch (Exception ex) {

			ex.printStackTrace();
		} finally {

			this.closeHttpResponse();
		}

		if (StringUtils.isNotBlank(redirectUrl)) {

			if (!StringUtils.startsWith(redirectUrl , "http://")) {

				redirectUrl = StringUtils.substringBeforeLast(url , "/") + "/" + redirectUrl;
			}

			headerMap.put("Referer" , url);

			Map redirectResultMap = this.doGet(redirectUrl , headerMap);
			Map redirectHeaderMap = (Map) redirectResultMap.get(HttpHandler.HEADER_KEY);

			resultMap.put(HttpHandler.REDIRECT_HEADER_KEY , redirectResultMap.get(HttpHandler.HEADER_KEY));
			resultMap.put(HttpHandler.REDIRECT_BODY_KEY   , redirectResultMap.get(HttpHandler.BODY_KEY));
		}

		return resultMap;
	}

	/**
	 * <p>获取响应内容
	 * 
	 * @param  httpResponse 响应对象
	 * 
	 * @return 与当前请求对应的响应内容字节数组
	 * @throws Exception 
	 * 
	 * @modify 窦海宁, 2017-01-18
	 */
	private byte[] getBody(HttpResponse httpResponse) throws Exception {

		byte[] bodyByteArray = null;

		Header contentEncodingHeader = httpResponse.getFirstHeader("Content-Encoding");
		if (contentEncodingHeader != null && StringUtils.indexOf(contentEncodingHeader.getValue().toLowerCase() , "gzip") > -1) {

			try {

				//建立gzip解压工作流
				bodyByteArray = IOUtils.toByteArray(new GZIPInputStream(httpResponse.getEntity().getContent()));
			} catch (Exception ex) {

				ex.printStackTrace();
			}
		} else {

			try {

				bodyByteArray = IOUtils.toByteArray(httpResponse.getEntity().getContent());
			} catch (IOException ex) {

				ex.printStackTrace();
			}
		}

		return bodyByteArray;
	}

	/**
	 * <p>添加查询字符串
	 * 
	 * @param  url            POST请求地址
	 * @param  queryStringMap 查询字符串参数容器
	 * 
	 * @return 拼装后的查询字符串
	 * @throws Exception 
	 * 
	 * @modify 窦海宁, 2015-10-18
	 */
	public String createUrl(String url , Map queryStringMap) throws Exception {

		StringBuffer queryStringBuffer = new StringBuffer(url);

		if (CollectionUtil.isNotEmpty(queryStringMap)) {

			//拼装查询字符串
			queryStringBuffer.append("?");
			Iterator iterator = queryStringMap.keySet().iterator();
			while (iterator.hasNext()) {

				Object key = iterator.next();
				try {

					key = URLEncoder.encode((String) key , this.charset);

					String value = null;
					if (queryStringMap.get(key) == null) {

						value = "";
					} else {

						value = URLEncoder.encode((String) queryStringMap.get(key) , this.charset);
					}

					queryStringBuffer.append(key).append("=").append(value);
				} catch (UnsupportedEncodingException ex) {

					ex.printStackTrace();
				}
				if (iterator.hasNext()) {

					queryStringBuffer.append("&");
				}
			}
		}

		return queryStringBuffer.toString();
	}

	/**
	 * <p>初始化Cookie网络环境(版本号、域名、路径信息,以会话ID变量为样本)
	 * 
	 * @modify 窦海宁, 2017-01-17
	 */
	private void initCookieEnvironment() throws Exception {

		List cookieList = this.cookieStore.getCookies();
		for (int i = 0 ; i < cookieList.size() ; i++) {

			BasicClientCookie cookie = (BasicClientCookie) cookieList.get(i);
			if (StringUtils.equalsIgnoreCase("JSESSIONID" , cookie.getName())) {

				this.cookiePath    = cookie.getPath();
				this.cookieDomain  = cookie.getDomain();
				this.cookieVersion = cookie.getVersion();
				break;
			}
		}
	}

	/**
	 * <p>添加请求Cookie
	 * 
	 * @param  cookieMap 请求Cookie参数容器
	 * 
	 * @modify 窦海宁, 2017-01-17
	 */
	private void addCookie(Map cookieMap) {

		if (CollectionUtil.isNotEmpty(cookieMap)) {

			//Cookie请求信息
			Iterator iterator = cookieMap.entrySet().iterator();
			while (iterator.hasNext()) {

				Entry entry = (Entry) iterator.next();

				BasicClientCookie cookie = new BasicClientCookie(entry.getKey().toString() , entry.getValue().toString());

				cookie.setPath(this.cookiePath);
				cookie.setDomain(this.cookieDomain);
				cookie.setVersion(this.cookieVersion);

				this.cookieStore.addCookie(cookie);
			}

			this.localContext.setCookieStore(this.cookieStore);
		}
	}

	/**
	 * <p>添加请求头
	 * 
	 * @param  headerMap   请求头参数容器
	 * @param  httpRequest 请求对象
	 * 
	 * @modify 窦海宁, 2017-02-13
	 */
	private void addHeader(Map headerMap , HttpRequest httpRequest) {

		if (CollectionUtil.isNotEmpty(headerMap)) {

			//头部请求信息
			Iterator iterator = headerMap.entrySet().iterator();
			while (iterator.hasNext()) {

				Entry entry = (Entry) iterator.next();
				if (entry.getKey() != null && entry.getValue() != null) {

					httpRequest.addHeader(entry.getKey().toString() , entry.getValue().toString());
				}
			}

			httpRequest.addHeader("Charset" , this.charset);
		}
	}

	/**
	 * <p>添加请求参数
	 * 
	 * @param  paramMap 请求参数容器
	 * @param  httpPost Post请求对象
	 * 
	 * @return 添加后的参数列表
	 * 
	 * @modify 窦海宁, 2017-02-13
	 */
	private HttpEntity addParam(Object param , HttpPost httpPost) {

		HttpEntity postEntity = null;

		if (param != null) {

			if (param instanceof String) {

				postEntity = new StringEntity((String) param , this.charset);
			} else if (param instanceof Map) {

				MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
				multipartEntityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
//				multipartEntityBuilder.setCharset(Charset.forName(this.charset));

				Map      paramMap    = (Map) param;
				Iterator keyIterator = paramMap.keySet().iterator();

				boolean containFile = false;
				while (keyIterator.hasNext()) {

					Object key   = keyIterator.next();
					Object value = paramMap.get(key);
					if (value instanceof String) {

						//文本处理
						StringBody stringBody = new StringBody((String) value , ContentType.TEXT_PLAIN);
						multipartEntityBuilder.addPart((String) key , stringBody);
					} else if (value instanceof File) {

						//文件处理
						FileBody fileBody = new FileBody((File) value);
						multipartEntityBuilder.addPart((String) key , fileBody);
						containFile = true;
					} else {

						//输出错误信息
					}
				}

//				if (containFile) {
//
//					multipartEntityBuilder.setContentType(ContentType.MULTIPART_FORM_DATA);
//				} else {
//
//					multipartEntityBuilder.setContentType(ContentType.APPLICATION_FORM_URLENCODED);
//				}

				postEntity = multipartEntityBuilder.build();
			} else {

				HttpHandler.logger.debug("this -> addParam : 请求参数类型不匹配,传入参数类型为 : " + param.getClass().getName());
				//此处应抛出异常
			}
		}

		return postEntity;
	}

	/**
	 * <p>关闭请求对象
	 * 
	 * @modify 窦海宁, 2017-02-06
	 */
	private void closeHttpResponse() {

		if (this.httpResponse != null) {

			try {

				this.httpResponse.close();
			} catch (Exception ex) {

				ex.printStackTrace();
			}
		}
	}

	/*对象变量Get、Set方法*/

	public void setCharset(String charset) {
		this.charset = charset;
	}

	public void setProxyUrl(String proxyUrl) {
		this.proxyUrl = proxyUrl;
	}

	public void setProxyPort(int proxyPort) {
		this.proxyPort = proxyPort;
	}

	public void setTimeout(int timeout) {
		this.timeout = timeout;
	}

	public void setCookiePath(String cookiePath) {
		this.cookiePath = cookiePath;
	}

}

猜你喜欢

转载自chong0660.iteye.com/blog/1923206