一、使用步骤
调用其他服务方法时,除了dubbo、rmq等方式外,还可以采取http方式调取对方服务的url,获取响应数据,可以采用HttpClient或CloseableHttpClient等接口实现http调用请求
使用HttpClient发送请求的一般步骤 ,如下所示:
(1)进行http连接配置,包括请求超时时间、读取响应时间、重试次数,最大请求数等配置
(2)根据请求方式和参数创建对应的http对象。有HttpPost、HttpGet创建请求方式方法,对于HttpPost对象而言,可调用setEntity(HttpEntity entity)方法来设置请求参数,HttpGet参数需要设置在url上
(3)创建HttpClient/CloseableHttpClient对象发送Http请求。调用HttpClient/CloseableHttpClient对象的execute(HttpUriRequest request)发送请求,该方法返回一个HttpResponse。
(4) 创建HttpResponse/CloseableHttpResponse对象接受返回对象。
(5)解析返回对象HttpResponse/CloseableHttpResponse参数。调用HttpResponse的getAllHeaders()、getHeaders(String name)等方法可获取服务器的响应头;调用HttpResponse/CloseableHttpResponse的getEntity()方法可获取HttpEntity对象,该对象包装了服务器的响应内容。程序可通过该对象获取服务器的响应内容。 (6)释放连接。无论执行方法是否成功,都必须释放连接
下面分别介绍使用HTTPClient和CloseableHTTPClient进行Get和Post请求的方式。
二、使用方法
1.准备条件
创建HttpClientUtil工具类,加载http连接配置文件
public static final String encoding;
private static final PoolingHttpClientConnectionManager connectionManager;
private static final CloseableHttpClient httpClient;
private static RequestConfig defaultRequestConfig;
private static final int defaultConnectTimeout;
private static final int defaultSocketTimeout;
static {
Properties p = new Properties();
InputStream inputStream = null;
try {
inputStream = HttpClientUtil.class.getClassLoader().getResourceAsStream("config/httputil.properties");
log.info("获取到http连接配置");
p.load(inputStream);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
}
}
}
//获取编码方式
encoding = p.getProperty("http.content.encoding");
//每个http请求连接接超时时间,可自己配置
defaultConnectTimeout = Integer.valueOf(p.getProperty("http.connection.timeout"));
//读取数据超时时间
defaultSocketTimeout = Integer.valueOf(p.getProperty("http.so.timeout"));
connectionManager = new PoolingHttpClientConnectionManager();
// http最大连接数
connectionManager.setMaxTotal(Integer.parseInt(p.getProperty("http.max.total.connections")));
// 每个路由基础的最大连接
connectionManager.setDefaultMaxPerRoute(Integer.parseInt(p.getProperty("http.default.max.connections.per.host")));
SocketConfig defaultSocketConfig = SocketConfig.custom().setSoTimeout(defaultSocketTimeout)
.setTcpNoDelay(Boolean.parseBoolean(p.getProperty("http.tcp.no.delay"))).build();
connectionManager.setDefaultSocketConfig(defaultSocketConfig);
//设置重试次数。默认为3次
httpClient = HttpClients.custom().setConnectionManager(connectionManager)
.setRetryHandler(new DefaultHttpRequestRetryHandler(Integer.parseInt(p.getProperty("retryCount")), false)).build();
defaultRequestConfig = RequestConfig.custom().setSocketTimeout(defaultSocketTimeout).setConnectTimeout(defaultConnectTimeout)
.setConnectionRequestTimeout(defaultConnectTimeout).build();
}
配置文件httputil.properties如下所示:
# \u8FDE\u63A5\u8D85\u65F6
http.connection.timeout=10000
# \u5E94\u7B54\u8D85\u65F6
http.so.timeout=50000
# \u7F51\u7EDC\u53C2\u6570
http.stale.check.enabled=true
http.tcp.no.delay=true
http.default.max.connections.per.host=100
http.max.total.connections=1000
# \u5B57\u7B26\u96C6
http.content.encoding=utf-8
retryCount=3
2.post方式传递参数
1)创建HttpPost对象
再添加连接超时时间配置,然后将请求参数根据编码方式封装在Entity里面。NameValuePair接收参数。用于http封装请求参数,将map中name-value转换为NameValuePair数组对象,然后通过UrlEncodedFormEntity将之转换为HttpEntity对象
public static String post(String httpUrl, Map<String, String> maps, String encoding, int socketTimeout) throws IOException {
// 创建httpPost
HttpPost httpPost = new HttpPost(httpUrl);
//网络超时设置
addHttpRequestConfig(httpPost, socketTimeout);
// 创建参数队列
List<NameValuePair> nameValuePairs = Lists.newArrayList();
for (String key : maps.keySet()) {
nameValuePairs.add(new BasicNameValuePair(key, maps.get(key)));
}
//将参数转换为固定格式
httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, encoding));
return sendHttpPost(httpPost);
}
也可以使用json方式请求,创建StringEntity对象,存放json类型的字符串数据
public static String postJson(String httpUrl, String json, int socketTimeout) throws IOException {
// 创建httpPost
HttpPost httpPost = new HttpPost(httpUrl);
addHttpRequestConfig(httpPost, socketTimeout);
// 设置参数
StringEntity stringEntity = new StringEntity(json, ContentType.APPLICATION_JSON);
httpPost.setEntity(stringEntity);
return sendHttpPost(httpPost);
}
2)发送http请求
封装好数据和定义好请求方式后,创建CloseableHttpClient或Httpclient对象来执行http连接,通过CloseableHttpResponse对象来接受返回对象
private static String sendHttpPost(HttpPost httpPost) throws IOException {
CloseableHttpResponse response = null;
String responseContent = null;
try {
// 执行请求
response = httpClient.execute(httpPost);
responseContent = extractReponseContent(response);
} finally {
//关闭请求连接
if (response != null) {
try {
response.close();
} catch (IOException e) {
log.error( "关闭连接失败");
}
}
}
return responseContent;
}
3)解析请求返回数据
private static String extractReponseContent(CloseableHttpResponse response) throws IOException {
HttpEntity entity;
int statusCode = response.getStatusLine().getStatusCode();
if (200 != statusCode) {
throw new RuntimeException("请求错误,statusCode:" + statusCode);
}
entity = response.getEntity();
return EntityUtils.toString(entity, encoding);
}
3.Get方式请求
1)创建HttpGet对象
有参数的话需要封装在url里面
public static String get(String url, Map<String, String> paramMap, String encoding, int socketTimeout)
throws IOException, URISyntaxException {
// 创建参数队列
List<NameValuePair> nameValuePairs = Lists.newArrayList();
for (String key : paramMap.keySet()) {
nameValuePairs.add(new BasicNameValuePair(key, paramMap.get(key)));
}
// Get请求
HttpGet httpGet = new HttpGet(url);
// 设置参数
addHttpRequestConfig(httpGet,socketTimeout);
// 设置参数
String str = EntityUtils.toString(new UrlEncodedFormEntity(nameValuePairs, encoding));
httpGet.setURI(new URI(httpGet.getURI().toString() + "?" + str));
return sendHttpGet(httpGet);
}
2)发送HttpGet请求和解析请求同2.2、2.3
三、实验测试
前提需要开通http请求接口的服务
创建请求参数并发送http请求
这里使用post方式传递参数,并用json格式传递,读取超时时间为5000ms
@Test
public void testHttpClient(){
UserQueryReqVO reqVO=new UserQueryReqVO();
reqVO.setAccount("11119844");
final String jsonReqVO= JSON.toJSONString(reqVO);
int timeoutSeconds=5;
log.info("开始http调用");
String response = null;
String url="http://10.45.40.199:8080/user/query";
long startTime = System.currentTimeMillis();
try {
//注意调用的http请求方法,get用get请求方式,post用post或者postJson方式,视请求方式和参数而定,返回的数据已拆分为纯数据
response = HttpClientUtil.postJson(url,jsonReqVO,timeoutSeconds * SystemConstant.ONE_SECOND_MILLISECONDS);
}catch (Exception e){
long endTime = System.currentTimeMillis();
log.error("调用http接口超时,耗时=[{}]",endTime-startTime,e);
throw new BizException(ResponseCode.CONNECTION_TIMEOUT);
}
Response res=JsonUtil.toObject(response,Response.class);
log.info("数据:{}",JsonUtil.toJsonString(res));
List<User> list=null;
if (res.getCode().equals("0")){
System.out.println("获取数据成功!"+JsonUtil.toJsonString(res));
list=( List<User>)res.getData();
System.out.println("数据为:"+list);
}else {
log.error("未获取到http数据");
System.out.println("获取数据失败"+JsonUtil.toJsonString(res));
}
}