HttpClient使用教程
一、 背景
1、原生的的java.net.HttpURLConnection
并不支持连接池,使用便捷性不好。
2、用 HttpURLConnection
发送json数据的教程如下:
/**
* 发送 json 数据的 post 请求
* @param json 数据内容
* @return 响应结果
*/
private String doJsonPost(String json) throws IOException {
URL url = new URL(String.format("http://%s:%d/api/v1/alerts", this.amHost, this.amPort));
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// HttpClient 6.0被抛弃了
String result = "";
BufferedReader reader = null;
try {
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Charset", "UTF-8");
// 设置文件类型:
conn.setRequestProperty("Content-Type","application/json; charset=UTF-8");
// 设置接收类型否则返回415错误
//conn.setRequestProperty("accept","*/*")此处为暴力方法设置接受所有类型,以此来防范返回415;
conn.setRequestProperty("accept","application/json");
// 往服务器里面发送数据
if (json != null && !TextUtils.isEmpty(json)) {
byte[] writebytes = json.getBytes();
// 设置文件长度
conn.setRequestProperty("Content-Length", String.valueOf(writebytes.length));
OutputStream outwritestream = conn.getOutputStream();
outwritestream.write(json.getBytes());
outwritestream.flush();
outwritestream.close();
log.info("doJsonPost: {}", conn.getResponseCode());
}
if (conn.getResponseCode() == 200) {
reader = new BufferedReader( new InputStreamReader(conn.getInputStream()));
result = reader.readLine();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}
二、HttpClient 使用
1、HttpClient 通过连接池创建连接
1、管理连接的基本单位是Route(路由),每个路由上都会维护一定数量的HTTP连接:
2、每次调用后必须执行 releaseConnection
3、路由可以理解为客户端机器到目标机器的一条线路
4、如果不给 httpclient
配置指定的连接管理器,httpclient
会自动使用PoolingHttpClientConnectionManager
作为连接管理器。
5、PoolingHttpClientConnectionManager默认的maxConnPerRoute和maxConnTotal分别是是2和20。
6、也就是对于每个服务器最多只会维护2个连接,看起来有点少。所以,在日常使用时我们尽量使用自己配置的连接管理器比较好。
2、扩展
- 连接池:
1、连接池技术作为创建和管理连接的缓冲池技术。
2、连接池管理的对象是长连接
3、有长连接的优势
-
长连接:是指客户端与服务器端一旦建立连接以后,可以进行多次数据传输而不需重新建立连接,
优势:1、省去了每次数据传输连接建立的时间开销,2、资源的访问控制 -
短连接:每次数据传输都需要客户端和服务器端建立一次连接
3、使用教程
package com.util;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* HttpClient 工具类
*/
@Slf4j
public class HttpClientUtil {
public static final String APPLICATION_JSON_VALUE = "application/json";
private static final Logger logger = log;
private static final Integer CONN_TIME_OUT = 3000;// 超时时间豪秒
private static final Integer SOCKET_TIME_OUT = 10000;
/** 每个路由的最大请求数,默认2 */
private static final Integer DEFAULT_MAX_PER_ROUTE = 40;
/** 最大连接数,默认20 */
private static final Integer MAX_TOTAL = 400;
private static HttpClient httpClient;
static {
// 请求配置
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(CONN_TIME_OUT)
.setConnectionRequestTimeout(CONN_TIME_OUT)
.setSocketTimeout(SOCKET_TIME_OUT)
.build();
// 管理 http连接池
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setDefaultMaxPerRoute(DEFAULT_MAX_PER_ROUTE);
cm.setMaxTotal(MAX_TOTAL);
httpClient = HttpClients.custom().setConnectionManager(cm).setDefaultRequestConfig(requestConfig).build();
}
public static String requestGet(String url, Map<String, String> paramsMap) throws Exception {
logger.info("GET request url:{} params:{}", url, paramsMap);
Long start = System.currentTimeMillis();
List<NameValuePair> params = initParams(paramsMap);
// Get请求
HttpGet httpGet = new HttpGet(url);
try {
// 设置参数
String str = EntityUtils.toString(new UrlEncodedFormEntity(params, StandardCharsets.UTF_8));
String uriStr = StringUtils.isEmpty(str) ? httpGet.getURI().toString() : httpGet.getURI().toString() + "?" + str;
httpGet.setURI(new URI(uriStr));
// 发送请求
HttpResponse response = httpClient.execute(httpGet);
logger.info("GET request url:{} response:{} time:{}",
url, response, System.currentTimeMillis() - start);
// 获取返回数据
return getSuccessRetFromResp(response, url, JSON.toJSONString(paramsMap));
} finally {
// 必须释放连接,负责连接用完后会阻塞
httpGet.releaseConnection();
}
}
/**
*
* @param url
* @param paramsMap
* @return 响应结果
*/
public static String requestPost(String url, Map<String, String> paramsMap) throws Exception {
logger.info("POST request url:{} params:{}", url, paramsMap);
Long start = System.currentTimeMillis();
List<NameValuePair> params = initParams(paramsMap);
HttpPost httpPost = new HttpPost(url);
try {
httpPost.setEntity(new UrlEncodedFormEntity(params, Consts.UTF_8));
HttpResponse response = httpClient.execute(httpPost);
logger.info("POST request url:{} response:{} time:{}",
url, response, System.currentTimeMillis() - start);
String retStr = getSuccessRetFromResp(response, url, JSON.toJSONString(paramsMap));
return retStr;
} finally {
httpPost.releaseConnection();
}
}
/**
* POST json 格式数据
*
*/
public static String requestPostJsonStr(String url, String json) throws Exception {
logger.info("POST request url:{} params:{}", url, json);
long start = System.currentTimeMillis();
HttpPost httpPost = new HttpPost(url);
try {
StringEntity entity = new StringEntity(json, Consts.UTF_8);
entity.setContentType(APPLICATION_JSON_VALUE);
httpPost.setEntity(entity);
HttpResponse response = httpClient.execute(httpPost);
logger.info("POST request url:{} response:{} time:{}", url, response, System.currentTimeMillis() - start);
return getSuccessRetFromResp(response, url, json);
} finally {
// 资源释放
httpPost.releaseConnection();
}
}
/**
* post json 格式数据
*
* @param url
* @param obj
* @return
* @throws Exception
*/
public static String requestPostJson(String url, Object obj) throws Exception {
String params = JSON.toJSONString(obj);
return requestPostJsonStr(url, params);
}
private static String getSuccessRetFromResp(HttpResponse response, String url, String params) throws Exception {
String retStr = "";
// 检验状态码,如果成功接收数据
int code = response.getStatusLine().getStatusCode();
if (code == 200) {
retStr = EntityUtils.toString(response.getEntity(), Consts.UTF_8);
} else {
throw new RuntimeException(String.format("Http request error:%s, url:%s, params:%s", response, url, params));
}
logger.info("Http request retStr:{}. url:{}", retStr, url);
return retStr;
}
private static List<NameValuePair> initParams(Map<String, String> paramsMap) {
List<NameValuePair> params = new ArrayList<NameValuePair>();
if (paramsMap == null)
return params;
for (Map.Entry<String, String> entry : paramsMap.entrySet()) {
params.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
return params;
}
}