HttpClient的基本使用
概述
HttpClient 是Apache Jakarta Common 下的子項目铡羡,可以用來提供高效的班利、最新的陈症、功能豐富的支持 HTTP 協(xié)議的客戶端編程工具包,并且它支持 HTTP 協(xié)議最新的版本和建議捺疼。
HttpClient相比JDK自帶的URLConnection外里,增加了易用性和靈活性怎爵,使客戶端發(fā)送Http請求變得更加容易,而且也方便開發(fā)測試接口盅蝗,大大提高開發(fā)的效率鳖链。
常用HTTP協(xié)議客戶端包括有:httpclient、restTemplate墩莫、okHttp
官網(wǎng):https://hc.apache.org/index.html
添加依賴
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
Get請求
1.無參數(shù)的GET請求
@Test
public void get() throws IOException {
// 創(chuàng)建HttpClient對象
CloseableHttpClient httpClient = HttpClients.createDefault();
// 創(chuàng)建HttpGet請求
HttpGet httpGet = new HttpGet("https://www.baidu.com");
// 響應(yīng)對象
CloseableHttpResponse response = null;
try {
// 使用HttpClient發(fā)起請求
response = httpClient.execute(httpGet);
// 判斷響應(yīng)狀態(tài)碼是否為200
if (response.getStatusLine().getStatusCode() == 200) {
// 獲取返回數(shù)據(jù)
HttpEntity httpEntity = response.getEntity();
String content = EntityUtils.toString(httpEntity, "UTF-8");
// 打印數(shù)據(jù)長度
log.info("content:{}", content);
}
} finally {
// 釋放連接
if (response != null) {
response.close();
}
httpClient.close();
}
}
2.帶參數(shù)的GET請求
HttpGet httpGet = new HttpGet("https://www.baidu.com/s?wd=java");
POST請求
1.無參數(shù)的POST請求
@Test
public void post() throws IOException {
// 創(chuàng)建HttpClient對象
CloseableHttpClient httpClient = HttpClients.createDefault();
// 創(chuàng)建HttpGet請求
HttpPost httpPost = new HttpPost("http://www.baidu.com");
// 響應(yīng)對象
CloseableHttpResponse response = null;
try {
// 使用HttpClient發(fā)起請求
response = httpClient.execute(httpPost);
// 判斷響應(yīng)狀態(tài)碼是否為200
if (response.getStatusLine().getStatusCode() == 200) {
// 獲取返回數(shù)據(jù)
HttpEntity httpEntity = response.getEntity();
String content = EntityUtils.toString(httpEntity, "UTF-8");
// 打印數(shù)據(jù)長度
log.info("content:{}", content);
}
} finally {
// 釋放連接
if (response != null) {
response.close();
}
httpClient.close();
}
}
2.帶參數(shù)的POST請求
public static void main(String[] args) throws Exception {
// 創(chuàng)建HttpClient對象
CloseableHttpClient httpClient = HttpClients.createDefault();
// 創(chuàng)建HttpPost對象芙委,設(shè)置url訪問地址
HttpPost httpPost = new HttpPost("https://fanyi.baidu.com/langdetect");
// 聲明List集合,封裝表單中的參數(shù)
List<NameValuePair> params = new ArrayList<NameValuePair>();
// 實際請求地址:https://fanyi.baidu.com/langdetect?query=Java
params.add(new BasicNameValuePair("query", "Java"));
// 創(chuàng)建表單的Entity對象,第一個參數(shù)是封裝好的表單數(shù)據(jù)狂秦,第二個參數(shù)是編碼
UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(params, "utf8");
//設(shè)置表單的Entity對象到Post請求中
httpPost.setEntity(formEntity);
CloseableHttpResponse response = null;
try {
// 使用HttpClient發(fā)起請求灌侣,獲取response
response = httpClient.execute(httpPost);
// 解析響應(yīng)
if (response.getStatusLine().getStatusCode() == 200) {
String content = EntityUtils.toString(response.getEntity(), "utf8");
log.info("content={}", content);
}
} finally {
// 關(guān)閉資源
response.close();
httpClient.close();
}
}
連接池
每次請求都要創(chuàng)建HttpClient,會有頻繁創(chuàng)建和銷毀的問題故痊,可以使用連接池來解決這個問題顶瞳。
public class HttpClientPool {
public static PoolingHttpClientConnectionManager getHttpClientPool(){
// 創(chuàng)建連接池管理器
PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager();
// 設(shè)置最大連接數(shù)
poolingHttpClientConnectionManager.setMaxTotal(100);
// 設(shè)置每個主機的最大連接數(shù)
poolingHttpClientConnectionManager.setDefaultMaxPerRoute(10);
return poolingHttpClientConnectionManager;
}
public static void main(String[] args) {
// 使用連接池管理器發(fā)起請求
PoolingHttpClientConnectionManager httpClientPool = HttpClientPool.getHttpClientPool();
// 從連接池中獲取HttpClient對象
CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(httpClientPool).build();
}
}
請求參數(shù)配置
對請求進行參數(shù)配置玖姑,如cookie設(shè)置愕秫,代理設(shè)置,以及常用的請求超時時間設(shè)置焰络。
public class HttpClientPool {
public static PoolingHttpClientConnectionManager getHttpClientPool() {
// 創(chuàng)建連接池管理器
PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager();
// 設(shè)置最大連接數(shù)
poolingHttpClientConnectionManager.setMaxTotal(100);
// 設(shè)置每個主機的最大連接數(shù)
poolingHttpClientConnectionManager.setDefaultMaxPerRoute(10);
return poolingHttpClientConnectionManager;
}
public static void main(String[] args) throws IOException {
// 使用連接池管理器發(fā)起請求
PoolingHttpClientConnectionManager httpClientPool = HttpClientPool.getHttpClientPool();
// 從連接池中獲取HttpClient對象
CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(httpClientPool).build();
HttpGet httpGet = new HttpGet("http://www.baidu.com");
// 配置請求信息
RequestConfig config = RequestConfig.custom()
// 創(chuàng)建連接的最長時間戴甩,單位是毫秒
.setConnectTimeout(1000)
// 設(shè)置獲取連接的最長時間,單位是毫秒
.setConnectionRequestTimeout(500)
// 設(shè)置數(shù)據(jù)傳輸?shù)淖铋L時間闪彼,單位是毫秒
.setSocketTimeout(10 * 1000)
.build();
// 給請求設(shè)置請求信息
httpGet.setConfig(config);
// 使用HttpClient發(fā)起請求甜孤,獲取response
CloseableHttpResponse execute = httpClient.execute(httpGet);
}
}
工具類封裝
HttpClientResult
/**
* Description: 封裝httpClient響應(yīng)結(jié)果
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class HttpClientResult implements Serializable {
/**
* 響應(yīng)狀態(tài)碼
*/
private int code;
/**
* 響應(yīng)數(shù)據(jù)
*/
private String content;
}
HttpClientUtils
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.*;
/**
* Description: httpClient工具類
*/
public class HttpClientUtils {
// 編碼格式榨汤。發(fā)送編碼格式統(tǒng)一用UTF-8
private static final String ENCODING = "UTF-8";
// 設(shè)置連接超時時間者祖,單位毫秒。
private static final int CONNECT_TIMEOUT = 6000;
// 請求獲取數(shù)據(jù)的超時時間(即響應(yīng)時間)额湘,單位毫秒描馅。
private static final int SOCKET_TIMEOUT = 6000;
/**
* 發(fā)送get請求把夸;不帶請求頭和請求參數(shù)
*
* @param url 請求地址
*/
public static HttpClientResult doGet(String url) throws Exception {
return doGet(url, null, null);
}
/**
* 發(fā)送get請求;帶請求參數(shù)
*
* @param url 請求地址
* @param params 請求參數(shù)集合
*/
public static HttpClientResult doGet(String url, Map<String, String> params) throws Exception {
return doGet(url, null, params);
}
/**
* 發(fā)送get請求铭污;帶請求頭和請求參數(shù)
*
* @param url 請求地址
* @param headers 請求頭集合
* @param params 請求參數(shù)集合
*/
public static HttpClientResult doGet(String url, Map<String, String> headers, Map<String, String> params) throws Exception {
// 創(chuàng)建httpClient對象
CloseableHttpClient httpClient = HttpClients.createDefault();
// 創(chuàng)建訪問的地址
URIBuilder uriBuilder = new URIBuilder(url);
if (params != null) {
Set<Map.Entry<String, String>> entrySet = params.entrySet();
for (Map.Entry<String, String> entry : entrySet) {
uriBuilder.setParameter(entry.getKey(), entry.getValue());
}
}
// 創(chuàng)建http對象
HttpGet httpGet = new HttpGet(uriBuilder.build());
/**
* setConnectTimeout:設(shè)置連接超時時間恋日,單位毫秒膀篮。
* setConnectionRequestTimeout:設(shè)置從connect Manager(連接池)獲取Connection
* 超時時間,單位毫秒岂膳。這個屬性是新加的屬性誓竿,因為目前版本是可以共享連接池的。
* setSocketTimeout:請求獲取數(shù)據(jù)的超時時間(即響應(yīng)時間)谈截,單位毫秒筷屡。 如果訪問一個接口,多少時間內(nèi)無法返回數(shù)據(jù)傻盟,就直接放棄此次調(diào)用速蕊。
*/
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(CONNECT_TIMEOUT).setSocketTimeout(SOCKET_TIMEOUT).build();
httpGet.setConfig(requestConfig);
// 設(shè)置請求頭
packageHeader(headers, httpGet);
try {
// 執(zhí)行請求并獲得響應(yīng)結(jié)果
return getHttpClientResult(httpClient, httpGet);
} finally {
// 釋放資源
close(httpClient);
}
}
/**
* 發(fā)送post請求;不帶請求頭和請求參數(shù)
*
* @param url 請求地址
*/
public static HttpClientResult doPost(String url) throws Exception {
return doPost(url, null, null);
}
/**
* 發(fā)送post請求娘赴;帶請求參數(shù)
*
* @param url 請求地址
* @param params 參數(shù)集合
*/
public static HttpClientResult doPost(String url, Map<String, String> params) throws Exception {
return doPost(url, null, params);
}
/**
* 發(fā)送post請求规哲;帶請求頭和請求參數(shù)
*
* @param url 請求地址
* @param headers 請求頭集合
* @param params 請求參數(shù)集合
*/
public static HttpClientResult doPost(String url, Map<String, String> headers, Map<String, String> params) throws Exception {
// 創(chuàng)建httpClient對象
CloseableHttpClient httpClient = HttpClients.createDefault();
// 創(chuàng)建http對象
HttpPost httpPost = new HttpPost(url);
/**
* setConnectTimeout:設(shè)置連接超時時間,單位毫秒诽表。
* setConnectionRequestTimeout:設(shè)置從connect Manager(連接池)獲取Connection
* 超時時間唉锌,單位毫秒。這個屬性是新加的屬性竿奏,因為目前版本是可以共享連接池的袄简。
* setSocketTimeout:請求獲取數(shù)據(jù)的超時時間(即響應(yīng)時間),單位毫秒泛啸。 如果訪問一個接口绿语,多少時間內(nèi)無法返回數(shù)據(jù),就直接放棄此次調(diào)用候址。
*/
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(CONNECT_TIMEOUT).setSocketTimeout(SOCKET_TIMEOUT).build();
httpPost.setConfig(requestConfig);
// 設(shè)置請求頭
/*httpPost.setHeader("Cookie", "");
httpPost.setHeader("Accept", "application/json");
httpPost.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36");*/
packageHeader(headers, httpPost);
// 封裝請求參數(shù)
packageParam(params, httpPost);
try {
// 執(zhí)行請求并獲得響應(yīng)結(jié)果
return getHttpClientResult(httpClient, httpPost);
} finally {
// 釋放資源
close(httpClient);
}
}
/**
* 發(fā)送put請求吕粹;不帶請求參數(shù)
*
* @param url 請求地址
*/
public static HttpClientResult doPut(String url) throws Exception {
return doPut(url, null);
}
/**
* 發(fā)送put請求;帶請求參數(shù)
*
* @param url 請求地址
* @param params 參數(shù)集合
*/
public static HttpClientResult doPut(String url, Map<String, String> params) throws Exception {
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPut httpPut = new HttpPut(url);
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(CONNECT_TIMEOUT).setSocketTimeout(SOCKET_TIMEOUT).build();
httpPut.setConfig(requestConfig);
packageParam(params, httpPut);
try {
return getHttpClientResult(httpClient, httpPut);
} finally {
close(httpClient);
}
}
/**
* 發(fā)送delete請求岗仑;不帶請求參數(shù)
*
* @param url 請求地址
*/
public static HttpClientResult doDelete(String url) throws Exception {
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpDelete httpDelete = new HttpDelete(url);
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(CONNECT_TIMEOUT).setSocketTimeout(SOCKET_TIMEOUT).build();
httpDelete.setConfig(requestConfig);
try {
return getHttpClientResult(httpClient, httpDelete);
} finally {
close(httpClient);
}
}
/**
* 發(fā)送delete請求匹耕;帶請求參數(shù)
*
* @param url 請求地址
* @param params 參數(shù)集合
*/
public static HttpClientResult doDelete(String url, Map<String, String> params) throws Exception {
if (params == null) {
params = new HashMap<>();
}
params.put("_method", "delete");
return doPost(url, params);
}
/**
* Description: 封裝請求頭
*/
public static void packageHeader(Map<String, String> params, HttpRequestBase httpMethod) {
// 封裝請求頭
if (params != null) {
Set<Map.Entry<String, String>> entrySet = params.entrySet();
for (Map.Entry<String, String> entry : entrySet) {
// 設(shè)置到請求頭到HttpRequestBase對象中
httpMethod.setHeader(entry.getKey(), entry.getValue());
}
}
}
/**
* Description: 封裝請求參數(shù)
*/
public static void packageParam(Map<String, String> params, HttpEntityEnclosingRequestBase httpMethod)
throws UnsupportedEncodingException {
// 封裝請求參數(shù)
if (params != null) {
List<NameValuePair> nvps = new ArrayList<>();
Set<Map.Entry<String, String>> entrySet = params.entrySet();
for (Map.Entry<String, String> entry : entrySet) {
nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
// 設(shè)置到請求的http對象中
httpMethod.setEntity(new UrlEncodedFormEntity(nvps, ENCODING));
}
}
/**
* Description: 獲得響應(yīng)結(jié)果
*/
public static HttpClientResult getHttpClientResult(CloseableHttpClient httpClient, HttpRequestBase httpMethod) throws IOException {
try (CloseableHttpResponse httpResponse = httpClient.execute(httpMethod)) {
// 獲取返回結(jié)果
if (httpResponse != null && httpResponse.getStatusLine() != null) {
String content = "";
if (httpResponse.getEntity() != null) {
content = EntityUtils.toString(httpResponse.getEntity(), ENCODING);
}
return new HttpClientResult(httpResponse.getStatusLine().getStatusCode(), content);
}
}
return new HttpClientResult(HttpStatus.SC_INTERNAL_SERVER_ERROR, null);
}
/**
* Description: 釋放資源
*/
public static void close(CloseableHttpClient httpClient) throws IOException {
if (httpClient != null) {
httpClient.close();
}
}
}
測試
public class HttpClientUtilsTest {
/**
* Description: 測試get無參請求
*/
@Test
public void testGet() throws Exception {
HttpClientResult result = HttpClientUtils.doGet("https://www.baidu.com");
System.out.println(result);
}
/**
* Description: 測試get帶參請求
*/
@Test
public void testGetWithParam() throws Exception {
Map<String, String> params = new HashMap<String, String>();
params.put("word", "java");
HttpClientResult result = HttpClientUtils.doGet("url", params);
System.out.println(result);
}
/**
* Description: 測試post帶請求頭不帶請求參數(shù)
*/
@Test
public void testPost() throws Exception {
Map<String, String> headers = new HashMap<String, String>();
headers.put("Cookie", "cokie");
headers.put("Accept", "application/json");
headers.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36");
HttpClientResult result = HttpClientUtils.doPost("url", headers, null);
System.out.println(result);
}
/**
* Description: 測試post帶參請求
*/
@Test
public void testPostWithParam() throws Exception {
Map<String, String> params = new HashMap<String, String>();
params.put("word", "java");
HttpClientResult result = HttpClientUtils.doPost("url", params);
System.out.println(result);
}
}