Java 实现发送 HTTP 请求,系列文章:
《Java使用原生HttpURLConnection实现发送HTTP请求》
《Java使用HttpClient5实现发送HTTP请求》
《SpringBoot使用RestTemplate实现发送HTTP请求》
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、拼接 URL
StringBuffer 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-data
httpPost.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}