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}


















