package utils.http; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.http.*; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpResponseException; import org.apache.http.client.ResponseHandler; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.*; import org.apache.http.conn.ConnectionPoolTimeoutException; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpRequestRetryHandler; import org.apache.http.impl.client.HttpClients; import org.apache.http.message.BasicHeader; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.SocketTimeoutException; import java.nio.charset.Charset; import java.util.Map; /** * HttpClient实体类 * 这个类是对Apache的org.apache.http.client.HttpClient的一层封装 *

* Created by littlelory on 02/11/2017. */ public class HttpClient { private Log log = LogFactory.getLog(HttpClient.class); //Apache httpclient实例 private org.apache.http.client.HttpClient httpClient; //client标识 private String key; private HttpClient(org.apache.http.client.HttpClient httpClient, String key) { this.httpClient = httpClient; this.key = key; } /** * post请求 * 向url参数传入的连接发送post请求,请求的Body内容由body参数决定 * * @param url 请求url * @param headerMap http header数据,key为header名,value为header值 * @param body 请求的Body内容 * @return 响应数据 * @throws IOException 请求过程中发生异常 */ public String doPost(String url, Map headerMap, String body) throws IOException { log.debug("[httpclient][" + key + "] to post, url = [" + url + "], headerMap = [" + headerMap + "], body = [" + body + "]."); HttpPost request = new HttpPost(url); return doHttpEntityEnclosingRequestBase(request, headerMap, body); } /** * get请求 * 发送get请求,请求的url会根据url参数和params参数共同决定 * 例如url参数="www.xxx.com",params参数="uid=1×tamp=1510557964", * 则最终的请求url="www.xxx.com?uid=1×tamp=1510557964" * * @param url 请求url * @param headerMap http header数据,key为header名,value为header值 * @param params 请求参数 * @return 响应数据 * @throws IOException 请求过程中发生异常 */ public String doGet(String url, Map headerMap, String params) throws IOException { log.debug("[httpclient][" + key + "] to get, url = [" + url + "], headerMap = [" + headerMap + "], params = [" + params + "]."); //创建请求实例 HttpGet request = new HttpGet(url + (params != null && params.length() > 0 ? "?" + params : "")); return doHttpRequestBase(request, headerMap); } /** * delete请求 * * @param url 请求url * @param headerMap http header数据,key为header名,value为header值 * @return 响应数据 * @throws IOException 请求过程中发生异常 */ public String doDelete(String url, Map headerMap) throws IOException { log.debug("[httpclient][" + key + "] to delete, url = [" + url + "], headerMap = [%s], params = [" + headerMap + "]."); HttpDelete request = new HttpDelete(url); return doHttpRequestBase(request, headerMap); } /** * 执行Get、Delete请求 * * @param request 请求实例 * @param headerMap 请求头数据 * @return 响应数据 * @throws ConnectionPoolTimeoutException 如果从connectionManager获取client的过程超时,会出现本异常 * @throws SocketTimeoutException 如果请求超时,会出现本异常 * @throws IOException 请求过程出现异常 */ private String doHttpRequestBase(HttpRequestBase request, Map headerMap) throws IOException { setHeaders(request, headerMap); return doRequest(request, responseHandler); } /** * 执行Post、Put、Patch请求 * 由于Post、Put、Patch三个method会有消息体,所以httpclient对这三个单独抽象,都属于org.apache.http.client.methods.HttpEntityEnclosingRequestBase的子类 * * @param request 请求实例 * @param headerMap 请求头数据 * @param body 消息体信息 * @return 响应数据 * @throws ConnectionPoolTimeoutException 如果从connectionManager获取client的过程超时,会出现本异常 * @throws SocketTimeoutException 如果请求超时,会出现本异常 * @throws IOException 请求过程出现异常 */ private String doHttpEntityEnclosingRequestBase(HttpEntityEnclosingRequestBase request, Map headerMap, String body) throws IOException { setHeaders(request, headerMap); if (body != null && body.length() > 0) { request.setEntity(new StringEntity(body)); } return doRequest(request, responseHandler); } private void setHeaders(HttpRequestBase request, Map headerMap) { if (headerMap == null || headerMap.size() == 0) return; int headerSize = headerMap.size(); Header[] headers = new Header[headerSize]; int index = 0; for (Map.Entry entry : headerMap.entrySet()) { headers[index] = new BasicHeader(entry.getKey(), entry.getValue()); index++; } request.setHeaders(headers); } private String doRequest(HttpRequestBase request, ResponseHandler handler) throws IOException { try { long start = System.currentTimeMillis(); String response = httpClient.execute(request, handler); long cost = System.currentTimeMillis() - start; log.debug("[httpclient][" + key + "][cost] request[" + request + "], postMethod cost time:" + cost + "ms"); return response; } catch (ConnectionPoolTimeoutException e) { log.warn("[httpcient][" + key + "][timeout] connection pool timeout, request[" + request + "], msg[" + e.getMessage() + "]."); throw e; } catch (SocketTimeoutException e) { log.warn("[httpcient][" + key + "][timeout] socket timeout, request[" + request + "], msg[" + e.getMessage() + "]."); throw e; } catch (IOException e) { log.error("[httpclient][" + key + "][error] url[%s], msg = [" + e.getMessage() + "].", e); throw e; } } //请求响应Handler private ResponseHandler responseHandler = new ResponseHandler() { @Override public String handleResponse(final HttpResponse response) throws IOException { StatusLine statusLine = response.getStatusLine(); HttpEntity entity = response.getEntity(); log.debug("[httpclient][" + key + "] response: statusLine[" + statusLine + "]."); if (statusLine.getStatusCode() != HttpStatus.SC_OK) { throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase()); } if (entity == null) { throw new ClientProtocolException("Response contains no content."); } ContentType contentType = ContentType.getOrDefault(entity); Charset charset = contentType.getCharset(); BufferedReader reader = new BufferedReader(charset == null ? new InputStreamReader(entity.getContent()) : new InputStreamReader(entity.getContent(), charset)); StringBuilder sb = new StringBuilder(); String line; while ((line = reader.readLine()) != null) sb.append(line).append("\n"); return sb.length() > 0 ? sb.substring(0, sb.length() - 1) : null; } }; /** * 创建HttpClient的Builder实例 * * @param connectionManager 管理此client的HttpClientManager * @param key 此client的标识 * @return Builder实例 */ public static Builder instance(HttpClientManager connectionManager, String key) { return new Builder(connectionManager, key); } //HttpClient的构造器 public static class Builder { //建立连接 超时时间 private int connectTimeout = 150; //等待响应 超时时间 private int socketTimeout = 150; //从connectManager获取连接 超时时间 private int connectRequestTimeout = 150; //重试次数 private int retryCount = 0; //重试开关 private boolean retryEnable = false; private final HttpClientManager connectionManager; private final String key; public Builder(HttpClientManager connectionManager, String key) { this.connectionManager = connectionManager; this.key = key; } public Builder connectTimeout(int timeout) { this.connectTimeout = timeout; return this; } public Builder socketTimeout(int socketTimeout) { this.socketTimeout = socketTimeout; return this; } public Builder connectRequestTimeout(int connectRequestTimeout) { this.connectRequestTimeout = connectRequestTimeout; return this; } public Builder retryCount(int retryCount) { if (retryCount > 0) { this.retryEnable = true; this.retryCount = retryCount; } return this; } public HttpClient build() { org.apache.http.client.HttpClient client = HttpClients .custom() .setConnectionManager(connectionManager.getConnectionManager()) .setDefaultRequestConfig( RequestConfig .custom() .setConnectTimeout(this.connectTimeout) .setSocketTimeout(this.socketTimeout) .setConnectionRequestTimeout(this.connectRequestTimeout) .build() ) .setRetryHandler(new DefaultHttpRequestRetryHandler(this.retryCount, this.retryEnable)) .build(); return new HttpClient(client, key); } } }