1、HttpClient5 的介绍
HttpClient5 是 Apache HttpComponents 项目中的一个重要组件,它是一个功能齐全且高度可定制的 HTTP 客户端库,专门用于发送 HTTP 请求、处理 HTTP 响应并支持各种 HTTP 协议特性。
以下是对 HttpClient5 的详细介绍:
- 多协议支持:HttpClient5 支持 HTTP/1.1 和 HTTP/2 协议,特别是 HTTP/2 的多路复用和流优先级等特性,提升了网络请求效率。
- 连接池管理:内置的连接池机制能提高并发处理性能,减少资源消耗。
- 多种认证机制:支持 Basic、Digest、NTLM、Kerberos 等多种认证方式,能够处理多种安全场景。
- Cookie管理:内置 Cookie 管理功能,能够自动处理服务端返回的 Cookie 并在后续请求中使用,模拟浏览器行为。
- SSL/TLS支持:支持 HTTPS,提供自定义 SSL/TLS 配置,确保通信的安全性。
- 易于扩展和定制:HttpClient5 的设计高度模块化,用户可以根据需要对连接管理、重定向策略、请求重试策略、代理设置等进行灵活定制。
- 代理支持:可以轻松配置 HTTP 或 SOCKS 代理,用于跨网络访问和隐私保护。
2、创建 HttpClient5 工具类
通过将常用的方法封装到工具类中,可以避免重复编写相同的代码,从而提高代码的复用性。
(1)添加 Maven 依赖
在项目的 pom.xml 配置文件中添加 HttpClient5 依赖。
<!-- HttpClient5 依赖 -->
<dependency><groupId>org.apache.httpcomponents.client5</groupId><artifactId>httpclient5</artifactId><version>5.4</version>
</dependency>
(2)创建工具类
创建 HttpClientUtil 类(基于 HttpClient5 的 HTTP 请求工具类)。
package com.pjb.consumer.util;import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.classic.methods.HttpUriRequestBase;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.entity.UrlEncodedFormEntity;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.HttpEntity;
import org.apache.hc.core5.http.HttpStatus;
import org.apache.hc.core5.http.NameValuePair;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.io.entity.StringEntity;
import org.apache.hc.core5.http.message.BasicNameValuePair;
import org.apache.hc.core5.util.Timeout;import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;/*** 基于 HttpClient5 的 HTTP 请求工具类* @author pan_junbiao**/
public class HttpClientUtil
{// 超时时间private final static int timeOut = 60000; //60秒/*** 发送 GET 请求并获取响应数据** @param url 请求地址* @param params 请求参数* @return 响应数据字符串*/public static String doGet(String url, Map<String, String> params){HttpGet httpGet = null; //请求对象CloseableHttpClient httpClient = null; //请求客户端CloseableHttpResponse httpResponse = null; //响应对象try{// 1、拼接 URLStringBuffer stringBuffer = new StringBuffer(url);if (params != null && !params.isEmpty()){stringBuffer.append("?");for (Map.Entry<String, String> entry : params.entrySet()){stringBuffer.append(entry.getKey()).append("=").append(entry.getValue()).append("&");}stringBuffer.deleteCharAt(stringBuffer.length() - 1);}URI targetUri = new URI(stringBuffer.toString());// 2、创建请求对象httpGet = new HttpGet(targetUri);// 请求配置实例(不需要可忽略)RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(Timeout.ofMilliseconds(timeOut)) // 设置连接请求超时时间.setResponseTimeout(Timeout.ofMilliseconds(timeOut)) // 设置响应超时时间.build();httpGet.setConfig(requestConfig);// 3、创建请求客户端httpClient = HttpClients.createDefault();// 4、执行请求操作,并返回响应结果httpResponse = httpClient.execute(httpGet);HttpEntity httpEntity = httpResponse.getEntity();String result = EntityUtils.toString(httpEntity);if (httpResponse.getCode() != HttpStatus.SC_OK){//记录错误日志String errorMessage = String.format("[执行异常]执行GET请求操作失败,状态码:%s,错误信息:%s", httpResponse.getCode(), result);System.out.println(errorMessage);throw new Exception(errorMessage);}return result;} catch (Exception ex){ex.printStackTrace();} finally{//释放资源releaseResource(httpGet, httpClient, httpResponse);}return null;}/*** 发送 POST 请求并获取响应数据** @param url 请求地址* @param params 请求参数* @return 响应数据字符串*/public static String doPost(String url, Map<String, String> params){HttpPost httpPost = null; //请求对象CloseableHttpClient httpClient = null; //请求客户端CloseableHttpResponse httpResponse = null; //响应对象try{// 1、创建 URL 对象URI targetUri = new URI(url);// 2、创建请求对象httpPost = new HttpPost(targetUri);// 请求配置实例(不需要可忽略)RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(Timeout.ofMilliseconds(timeOut)) // 设置连接请求超时时间.setResponseTimeout(Timeout.ofMilliseconds(timeOut)) // 设置响应超时.build();httpPost.setConfig(requestConfig);// 设置请求头httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded");// 设置请求格式 multipart/form-datahttpPost.addHeader("Content-type", "multipart/form-data;boundary=" + UUID.randomUUID().toString());httpPost.addHeader("Accept", "*/*");// UTF-8 解决中文乱码httpPost.addHeader("Accept-Encoding", "UTF-8");httpPost.addHeader("User-Agent", " Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36");// 3、创建请求客户端httpClient = HttpClients.createDefault();// 4、写入请求体List<NameValuePair> paramList = new ArrayList<>();if (params != null && !params.isEmpty()){for (Map.Entry<String, String> entry : params.entrySet()){BasicNameValuePair nameValuePair = new BasicNameValuePair(entry.getKey(), entry.getValue());paramList.add(nameValuePair);}}UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(paramList, StandardCharsets.UTF_8);httpPost.setEntity(urlEncodedFormEntity);// 5、执行请求操作,并返回响应结果httpResponse = httpClient.execute(httpPost);HttpEntity httpEntity = httpResponse.getEntity();String result = EntityUtils.toString(httpEntity);if (httpResponse.getCode() != HttpStatus.SC_OK){//记录错误日志String errorMessage = String.format("[执行异常]执行POST请求操作失败,状态码:%s,错误信息:%s", httpResponse.getCode(), result);System.out.println(errorMessage);throw new Exception(errorMessage);}return result;} catch (Exception ex){ex.printStackTrace();} finally{//释放资源releaseResource(httpPost, httpClient, httpResponse);}return null;}/*** 发送 JSON 格式的 POST 请求并获取响应数据** @param url 请求地址* @param jsonParam JSON格式的请求参数* @return 响应数据字符串*/public static String doJsonPost(String url, String jsonParam){HttpPost httpPost = null; //请求对象CloseableHttpClient httpClient = null; //请求客户端CloseableHttpResponse httpResponse = null; //响应对象try{// 1、创建 URL 对象URI targetUri = new URI(url);// 2、创建请求对象httpPost = new HttpPost(targetUri);// 请求配置实例(不需要可忽略)RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(Timeout.ofMilliseconds(timeOut)) // 设置连接请求超时时间.setResponseTimeout(Timeout.ofMilliseconds(timeOut)) // 设置响应超时.build();httpPost.setConfig(requestConfig);// 设置请求头httpPost.addHeader("Content-Type", "application/json");httpPost.addHeader("Accept-Encoding", "UTF-8");// 3、创建请求客户端httpClient = HttpClients.createDefault();// 3、写入请求体StringEntity entity = new StringEntity(jsonParam, StandardCharsets.UTF_8);httpPost.setEntity(entity);// 4、执行请求操作,并返回响应结果httpResponse = httpClient.execute(httpPost);HttpEntity httpEntity = httpResponse.getEntity();String result = EntityUtils.toString(httpEntity);if (httpResponse.getCode() != HttpStatus.SC_OK){//记录错误日志String errorMessage = String.format("[执行异常]执行POST请求操作失败,状态码:%s,错误信息:%s", httpResponse.getCode(), result);System.out.println(errorMessage);throw new Exception(errorMessage);}return result;} catch (Exception ex){ex.printStackTrace();} finally{//释放资源releaseResource(httpPost, httpClient, httpResponse);}return null;}/*** 释放资源*/private static void releaseResource(HttpUriRequestBase httpRequest, CloseableHttpClient httpClient, CloseableHttpResponse httpResponse){if (httpRequest != null){try{httpRequest.reset();} catch (Exception e){System.out.println("关闭请求对象失败");}}if (httpClient != null){try{httpClient.close();} catch (IOException e){System.out.println("关闭请求客户端失败");}}if (httpResponse != null){try{httpResponse.close();} catch (IOException e){System.out.println("关闭响应对象失败");}}}
}
3、综合实例
【实例】实现用户信息的查询、新增、修改、删除接口,并使用 HttpClient5 实现接口的请求。
(1)在 controller 层,创建用户信息控制器类,实现查询、新增、修改、删除接口。
package com.pjb.business.controller;import com.pjb.business.entity.UserInfo;
import com.pjb.business.exception.ApiResponseException;
import com.pjb.business.model.ApiModel.ApiResponseCode;
import com.pjb.business.model.ApiModel.ApiResponseResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;/*** 用户信息控制器类* @author pan_junbiao**/
@RestController
@RequestMapping("/user")
@Api(description = "用户信息控制器")
public class UserController
{/*** 查询用户信息*/@ApiOperation(value = "查询用户信息")@RequestMapping(value = "/getUserInfo", method = RequestMethod.GET)public ApiResponseResult<UserInfo> getUserInfo(Long userId){if (userId <= 0){//使用:全局异常处理throw new ApiResponseException(ApiResponseCode.PARAMETER_ERROR);}UserInfo userInfo = new UserInfo();userInfo.setUserId(userId);userInfo.setUserName("pan_junbiao的博客");userInfo.setBlogName("您好,欢迎访问 pan_junbiao的博客");userInfo.setBlogUrl("https://blog.csdn.net/pan_junbiao");//使用:统一返回值return new ApiResponseResult(ApiResponseCode.SUCCESS, userInfo);}/*** 新增用户信息*/@ApiOperation(value = "新增用户信息")@RequestMapping(value = "/addUserInfo", method = RequestMethod.POST)public ApiResponseResult<Boolean> addUserInfo(@RequestBody UserInfo userInfo){if (userInfo == null || userInfo.getUserName() == null || userInfo.getUserName().length() == 0){//使用:全局异常处理throw new ApiResponseException(ApiResponseCode.PARAMETER_ERROR);}//使用:统一返回值return new ApiResponseResult(ApiResponseCode.SUCCESS, true);}/*** 修改用户信息*/@ApiOperation(value = "修改用户信息")@RequestMapping(value = "/updateUserInfo", method = RequestMethod.POST)public ApiResponseResult<Boolean> updateUserInfo(@RequestBody UserInfo userInfo){if (userInfo == null && userInfo.getUserId() <= 0){//使用:全局异常处理throw new ApiResponseException(ApiResponseCode.PARAMETER_ERROR);}//使用:统一返回值return new ApiResponseResult(ApiResponseCode.SUCCESS, true);}/*** 删除用户信息*/@ApiOperation(value = "删除用户信息")@RequestMapping(value = "/deleteUserInfo", method = RequestMethod.POST)public ApiResponseResult<Boolean> deleteUserInfo(Long userId){if (userId <= 0){//使用:全局异常处理throw new ApiResponseException(ApiResponseCode.PARAMETER_ERROR);}//使用:统一返回值return new ApiResponseResult(ApiResponseCode.SUCCESS, true);}
}
(2)使用 HttpClient5 发送 Get 请求,查询用户信息。
/*** 使用 HttpClient5 发送 Get 请求,查询用户信息*/
@Test
public void getUserInfo()
{//请求地址String url = "http://localhost:8085/user/getUserInfo";//请求参数Map<String, String> params = new HashMap<>();params.put("userId", "1");//发送 HTTP 的 Get 请求(核心代码)String httpResult = HttpClientUtil.doGet(url, params);//反序列化JSON结果ApiResponseResult<UserInfo> responseResult = JacksonUtil.getJsonToGenericityBean(httpResult, ApiResponseResult.class, UserInfo.class);UserInfo userInfo = responseResult.getData();System.out.println("响应JSON结果:" + httpResult);System.out.println("响应结果编码:" + responseResult.getCode());System.out.println("响应结果信息:" + responseResult.getMessage());System.out.println("用户编号:" + userInfo.getUserId());System.out.println("用户名称:" + userInfo.getUserName());System.out.println("博客信息:" + userInfo.getBlogName());System.out.println("博客地址:" + userInfo.getBlogUrl());
}
执行结果:
(3)使用 HttpClient5 发送 JSON 格式的 POST 请求,新增用户信息。
/*** 使用 HttpClient5 发送 JSON 格式的 POST 请求,新增用户信息*/
@Test
public void addUserInfo()
{//请求地址String url = "http://localhost:8085/user/addUserInfo";//请求参数UserInfo userInfo = new UserInfo();userInfo.setUserId(2L);userInfo.setUserName("pan_junbiao的博客");userInfo.setBlogName("您好,欢迎访问 pan_junbiao的博客");userInfo.setBlogUrl("https://blog.csdn.net/pan_junbiao");String json = JacksonUtil.getBeanToJson(userInfo);//发送 JSON 格式的 POST 请求(核心代码)String httpResult = HttpClientUtil.doJsonPost(url, json);System.out.println("响应结果:" + httpResult);
}
执行结果:
响应结果:{"code":200000,"message":"操作成功","data":true}
(4)使用 HttpClient5 发送 POST 请求,删除用户信息。
/*** 使用 HttpClient5 发送 POST 请求,删除用户信息*/
@Test
public void deleteUserInfo()
{//请求地址String url = "http://localhost:8085/user/deleteUserInfo";//请求参数Map<String, String> params = new HashMap<>();params.put("userId","3");//发送 HTTP 的 POST 请求(核心代码)String httpResult = HttpClientUtil.doPost(url, params);System.out.println("响应结果:" + httpResult);
}
执行结果:
响应结果:{"code":200000,"message":"操作成功","data":true}