Apache HttpClient 详解

2023-05-16

1、简介

HttpClient 是 Apache Jakarta Common 下的子项目,用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。HttpClient 已经应用在很多的项目中,比如 Apache Jakarta 上很著名的另外两个开源项目 Cactus 和 HTMLUnit 都使用了 HttpClient。

HttpClient 相比传统 JDK 自带的 URLConnection,增加了易用性和灵活性,它不仅是客户端发送 HTTP 请求变得容易,而且也方便了开发人员测试接口(基于 HTTP 协议的),即提高了开发的效率,也方便提高代码的健壮性。因此熟练掌握 HttpClient 是很重要的必修内容,掌握 HttpClient 后,相信对于 HTTP 协议的了解会更加深入。

2、引入依赖

HttpClient 是三方工具,首先需要引入依赖。如下:

<!-- 此处使用的是 5.x 版本,可以根据自身情况引入版本 -->
<dependency>
     <groupId>org.apache.httpcomponents.client5</groupId>
     <artifactId>httpclient5</artifactId>
     <version>5.1.1</version>
</dependency>

3、获取客户端

在使用时,首先需要 获取 HttpClient 对象,有如下几种获取方式

  1. 默认创建方式

    // 获取默认配置的 HttpClient 
    CloseableHttpClient httpClient = HttpClients.createDefault();
    
  2. 根据系统配置创建

    // 此种方式是通过 根据 系统配置创建 HttpClient
    CloseableHttpClient httpClient = HttpClients.createSystem();
    

    在项目启动时可以通过设置如下JVM启动参数:

    • http.agent 配置 userAgent
    • http.keepAlive 配置 keepAlive 数据
  3. 自定义创建

    // 此种方式可以在创建时 设置一些默认值
    CloseableHttpClient  httpClient = HttpClients.custom()
                         .setDefaultHeaders(Collections.emptyList())   // 设置默认请求头
                         .setDefaultRequestConfig(RequestConfig.DEFAULT)  // 设置默认配置
                         .build();
    

4、配置参数

HttpClient 可以通过在创建 HttpClient 对象时就设置全局配置,也可以为单个请求设置请求配置。

  1. 创建配置对象

      //  创建请求配置信息
    RequestConfig  requestConfig = RequestConfig.custom()
         // 设置连接超时时间
        .setConnectTimeout(Timeout.of(3000, TimeUnit.MILLISECONDS))
        // 设置响应超时时间
        .setResponseTimeout(3000, TimeUnit.MILLISECONDS) 
        // 设置从连接池获取链接的超时时间
        .setConnectionRequestTimeout(3000, TimeUnit.MILLISECONDS)
        .build();
    
    
    
  2. 设置全局配置

    // 此种方式可以在创建时 设置一些默认值
    CloseableHttpClient  httpClient = HttpClients.custom()
                         .setDefaultHeaders(Collections.emptyList())   // 设置默认请求头
                         .setDefaultRequestConfig(requestConfig)  // 设置默认配置
                         .build();
    
  3. 单个请求设置配置

    // 创建 GET 请求对象
    HttpGet httpGet = new HttpGet(uri);
    
    // 设置请求参数
    httpGet.setConfig(requestConfig);
    

5、设置请求头信息

在请求时,经常会遇到设置自定义请求头,或者更改 Conent-Type 的值,可以通过如下两种方式设置:

  1. 设置公共请求头

    List<Header> headers = new ArrayList<>();
    headers.add(new BasicHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON));
    headers.add(new BasicHeader(HttpHeaders.ACCEPT_ENCODING, "gzip, x-gzip, deflate"));
    headers.add(new BasicHeader(HttpHeaders.CONNECTION, "keep-alive"));
    
    // 创建 一个默认的 httpClient
    CloseableHttpClient  httpClient = HttpClients.custom()
        .setDefaultHeaders(headers)   // 设置默认请求头
        .build()
    
  2. 单个请求设置请求头

    // 创建 POST 请求
    HttpPost httpPost = new HttpPost(uri);
    // 添加 Content-Type 请求头
    httpPost.addHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED);
    // 添加 accept 请求头
    httpPost.addHeader(new BasicHeader(HttpHeaders.ACCEPT, "*/*"));
    

6、发送请求

GET 请求

GET请求的所有参数是直接拼接在 URL 后面的,在 HttpClient 中 有两种方式可以实现,如下所示:

  1. 请求参数直接拼接在请求路径后面

    String name = URLEncoder.encode("张三", "utf-8");
    // 请求路径及参数
    String url = "http://localhost:10010/user/params?age=20&name=" + name;
    
    // 创建 GET 请求对象
    HttpGet httpGet = new HttpGet(url);
    // 调用 HttpClient 的 execute 方法执行请求
    CloseableHttpResponse response = httpClient.execute(httpGet);
    // 获取请求状态
    int code = response.getCode();
    // 如果请求成功
    if(code == HttpStatus.SC_OK){
        LOGGER.info("响应结果为:{}", EntityUtils.toString(response.getEntity()));
    }
    
  2. 通过 URIBuilder 构建请求路径

    
    // 构建请求路径,及参数
    URL url = new URL("http://localhost:10010/user/params");
    URI uri = new URIBuilder()
        .setScheme(url.getProtocol())
        .setHost(url.getHost())
        .setPort(url.getPort())
        .setPath(url.getPath())
        // 构建参数
        .setParameters(
            new BasicNameValuePair("name", "张三"),
            new BasicNameValuePair("age", "20")
         ).build();
    
    // 创建 GET 请求对象
    HttpGet httpGet = new HttpGet(uri);
    // 调用 HttpClient 的 execute 方法执行请求
    CloseableHttpResponse response = httpClient.execute(httpGet);
    // 获取请求状态
    int code = response.getCode();
    // 如果请求成功
    if(code == HttpStatus.SC_OK){
        LOGGER.info("响应结果为:{}", EntityUtils.toString(response.getEntity()));
    }
    

POST 请求

众所周知,HTTP 中的 POST 请求的数据是包含在请求体中的。在 HttpClient 中 POST 请求发送数据是通过,调用 HttpPost 类的 setEntity(HttpEntity entity) 方法设置消息内容的。

  1. 发送 JSON 数据

    HttpClient 中发送 JSON 数据可以使用 StringHttpEntity 类实现,如下所示:

    // 请求参数
    String url = "http://localhost:10010/user/body";
    // 创建 GET 请求对象
    HttpPost httpPost = new HttpPost(url);
    // 构建对象
    User user = new User();
    user.setName("张三")
        .setAge(20)
        .setAddress(new Address()
                    .setCounty("中国")
                    .setCity("北京"))
        .setAihao(Arrays.asList("跑步", "爬山", "看书"));
    
    // 创建 字符串实体对象
    HttpEntity httpEntity = new StringEntity(JSON.toJSONString(user));
    httpPost.setEntity(httpEntity);
    
    // 发送 POST 请求
    httpClient.execute(httpPost);
    
  2. 模拟form表单数据

    在实际使用时,可以存在 需要模拟 form 表单的情况进行请求数据,在 HttpClent 中也可以很方便的实现 form 的提交功能。操作步骤如下:

    • 修改 contentType

      // 创建 ContentType 对象为 form 表单模式 
      ContentType contentType = ContentType.create("application/x-www-form-urlencoded", StandardCharsets.UTF_8);
      // 添加到 HttpPost 头中
      httpPost.setHeader(HttpHeaders.CONTENT_TYPE, contentType);
      
    • 创建请求数据 HttpEntity

      // 方式一、自己拼接请求数据,并且创建 StringEntity 对象
      String query = "name="+ URLEncoder.encode("张三", "utf-8") +"&age=20";
      HttpEntity httpEntity = new StringEntity(query);
      
      // 方式二、通过UrlEncodedFormEntity 创建 HttpEntity
      HttpEntity httpEntity = new UrlEncodedFormEntity(
          Arrays.asList(new BasicNameValuePair("name", "张三"),
                        new BasicNameValuePair("age", "20")),
          StandardCharsets.UTF_8
      );
      
      // 把 HttpEntity 设置到 HttpPost 中
      httpPost.setEntity(httpEntity);
      

    完整代码如下所示:

    
    // 创建 POST 请求对象
    HttpPost httpPost = new HttpPost("http://localhost:10010/user/map");
    /*String query = "name="+ URLEncoder.encode("张三", "utf-8") +"&age=20";
            HttpEntity httpEntity = new StringEntity(query);*/
    
    HttpEntity httpEntity = new UrlEncodedFormEntity(
        Arrays.asList(new BasicNameValuePair("name", "张三"),
                      new BasicNameValuePair("age", "20")),
        StandardCharsets.UTF_8
    );
    
    // 设置请求数据
    httpPost.setEntity(httpEntity);
    // 设置请求头
    ContentType contentType = ContentType.APPLICATION_FORM_URLENCODED.withCharset(StandardCharsets.UTF_8);
    httpPost.setHeader(HttpHeaders.CONTENT_TYPE, contentType);
    // 调用 HttpClient 的 execute 方法执行请求
    CloseableHttpResponse response = httpClient.execute(httpPost);
    // 获取请求状态
    int code = response.getCode();
    // 如果请求成功
    if(code == HttpStatus.SC_OK){
        LOGGER.info("响应结果为:{}", EntityUtils.toString(response.getEntity()));
    }
    

7、上传下载

上传

在 HttpClient 中实现上传功能是非常方便的,可以通过 MultipartEntityBuilder直接构建 HttpEntity 即可。

//要上传的文件
File file = new File("F:/20150703212056_Yxi4L.jpeg");

// 创建对象
MultipartEntityBuilder builder = MultipartEntityBuilder.create();

// 添加二进制消息体
builder.addBinaryBody("file", file);

// 也可以添加文本消息
ContentType contentType = ContentType.TEXT_PLAIN.withCharset(StandardCharsets.UTF_8);
builder.addTextBody("name", "张三", contentType);

// 通过 MultipartEntityBuilder 构建消息体
HttpEntity httpEntity = builder.build();
HttpPost httpPost = new HttpPost("http://localhost:10010/user/upload");
httpPost.setEntity(httpEntity);
CloseableHttpResponse response = httpClient.execute(httpPost);
// 获取请求状态
int code = response.getCode();
// 如果请求成功
if(code == HttpStatus.SC_OK){
    LOGGER.info("响应结果为:{}", EntityUtils.toString(response.getEntity()));
}

下载

HttpClient 中的下载也相当简单,只需要发送请求,判断请求成功后,读取输入流,然后保存到响应的路径下即可,如下:

// 请求下载路径
HttpGet httpGet = new HttpGet("http://localhost:10010/user/downLoad");
CloseableHttpResponse response = httpClient.execute(httpGet);

// 如果请求成功
if (response.getCode() == HttpStatus.SC_OK){

    // 获取下载文件的文件名,此处的 File-Name 头信息,需要在服务端进行自定义
    Header header = response.getFirstHeader("File-Name");
    String value = header.getValue();

    // 读取数据
    byte[] bytes = EntityUtils.toByteArray(response.getEntity());
    try (OutputStream outputStream = new FileOutputStream("F:/" + value);){
        outputStream.write(bytes);
        outputStream.flush();
    }
}

8、响应处理

在 HttpClient 中把响应封装成了 CloseableHttpResponse 对象,在此对象中可以获取如下数据:

  1. getCode() 获取响应状态
  2. getEntity() 获取响应数据
 // 如果请求成功
if(code == HttpStatus.SC_OK){
    LOGGER.info("响应结果为:{}", EntityUtils.toString(response.getEntity()));
}

HttpClient 提供了 EntityUtils工具类,可以很好的把 响应的 HttpEntity 转换为 字节数组或者字符串

// 转换为字符串
EntityUtils.toString(response.getEntity());

// 转换为字节数组
EntityUtils.toByteArray(response.getEntity());

除了上述外,还可以在 调用 HttpClient 的 execute()方法时 传入,响应处理器,返回自定义的数据类型。如下所示,是返回一个 自定义的 Response 对象

// 自定义响应对象
@Data
@Accessors(chain = true)
class  Response {
    // 响应状态
    private int code;
    // 响应描述
    private String msg;
    // 响应体
    private String body;
}

// 调用  execute 时自定义 响应处理类
 Response execute = httpClient.execute(httpGet, response -> {
            return new Response().setCode(response.getCode())
                .setMsg(response.getReasonPhrase())
                .setBody(EntityUtils.toString(response.getEntity(),                 
                                              StandardCharsets.UTF_8));
        });

9、会话保持

在实际项目中,经常会遇到需要先登录然后才能进行访问其他接口,那么, 在 HttpClient 中提供了 HttpClientContext 类,可以很好的实现,会话保持功能。

  • 创建HttpClientContext
  • 在 execute() 方法中传入 第一步创建的对象

如下所示:

// 创建 HttpClientContext对象
HttpContext httpContext = new BasicHttpContext();
httpContext.setAttribute("name", "zhangsan");
HttpClientContext httpClientContext = HttpClientContext.adapt(httpContext);

// 登录
httpClient.execute(new HttpPost(""), httpClientContext);

// 获取数据
httpClient.execute(new HttpGet(""), httpClientContext);

10、总结

这里只是 HttpClient 的使用做了简单的介绍,起到抛砖引玉的作用,其实,HttpClient 提供的功能非常强大的,在接下来会对 HttpClient 层层剖析,慢慢揭开 其神秘面纱。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Apache HttpClient 详解 的相关文章

随机推荐

  • Linux-虚拟网络设备-veth pair

    基本概念 Virtual Ethernet CableBidirectional FIFOOften used to cross namespaces Linux container 中用到一个叫做veth的东西 xff0c 这是一种新的设
  • openstack-neutron-OVS agent(持续更新)

    概述 ML2Plugin的主要工作是管理虚拟网络资源 xff0c 保证数据正确无误 xff0c 具体物理设备的设置则由Agent完成 L2Agent通常运行在Hypervisor xff0c 与neutron server通过RPC通信 x
  • VUE中使用EventSource接收服务器推送事件

    Vue项目中 xff0c EventSource触发的事件中this指向变了 使用const that 61 this xff0c 然后在EventSource触发的事件中使用that if typeof EventSource 61 61
  • VNC

    一 安装tigervnc server 二 配置登录帐号 三 生成xstartup与log日志 注意 xff1a 如果没有使用vncserver来 设置密码 xff0c 则service vncserver restart 是不会成功的 这
  • DirectUI框架GUIFW

    前言 guifw是一款基于GDI 43 的DirectUI皮肤引擎 xff0c 借鉴了DuiLib和Qt的思想 效果预览 xff1a http download csdn net detail sllins 7707771 代码已开源 xf
  • keil 提示internal command error和no sw device

    1 使用keil烧录软件的时候 xff0c jlink stlink无法识别到芯片 需要排查的问题 1 xff09 换条线 2 xff09 是不是有程序禁用了Seral Wire xff1a 使用cubeide cubeMX xff0c 容
  • 多线程编程模式之Single Threaded Execution 模式

    一 Single Threaded Execution 模式介绍 简单的来说 xff0c Single threaded execution 模式描述了在一种多线程环境下各个线程对于公用资源的使用方式 任一时刻 xff0c 只有一个线程可以
  • NVIDIA Jetson TX2 查看系统相关+运行demo

    1 查看Jetson TX2 L4T版本 xff1a head n 1 etc nv tegra release 2 查看系统版本 xff1a cat etc lsb release 3 查看系统内核 xff1a uname a 4 查看内
  • Docker镜像迁移至新的服务器(全部数据)

    1 找到你想移动的 Docker 容器的 ID 2 提交你的变更 xff0c 并且把容器保存成镜像 xff0c 命名为 newimage docker commit span class token number 3 span a09b25
  • 配置VNC环境在windows主机访问阿里云linux服务器

    配置VNC环境在windows主机访问阿里云linux服务器 虽然作为服务器使用更多的是使用字符终端连接服务器 xff0c 进行操作 xff0c 因为图形界面很消耗性能和资源 xff0c 但有的时候使用图形界面进行操作更为便捷 xff0c
  • pythondataframe输出小结

    在使用dataframe时遇到datafram在列太多的情况下总是自动换行显示的情况 xff0c 导致数据阅读困难 xff0c 效果如下 xff1a coding utf 8 import numpy as np import pandas
  • 聊聊 Redis 为什么构建自己的简单动态字符串 SDS

    我们知道 xff0c Redis 支持字符串 哈希 列表 集合和有序集合五种基本类型 那么我们如何把图片 音频 视频或者压缩文件等二进制数据保存到 Redis 中呢 xff1f 之前在使用 Memcached 缓存这类数据时是把它们转换成
  • 聊聊 Redis 高可用之持久化AOF和RDB分析

    Redis 持久化概述 Redis 是内存数据库 xff0c 数据都是存储在内存中 xff0c 为了避免进程退出导致数据的永久丢失 xff0c 需要定期将 Redis 中的数据以某种形式把内存中的数据保存到磁盘中 xff1b 当 Redis
  • mysqldump: Got error: 1044: Access denied for user XXXX when doing LOCK TABLES

    一 报错信息 在使用mysqldump 执行远程备份数据库的时候报如下错误 xff1a mysqldump Got error span class token number 1044 span Access denied span cla
  • jmap -heap [pid]运行报:Error attaching to process: sun.jvm.hotspot.debugger.DebuggerException(不允许的操作)

    一 运行环境 操作系统 xff1a Ubuntu 5 4 0 6 Java版本 xff1a JDK8 二 执行命令 jmap heap span class token punctuation span pid号 span class to
  • chkconfig: command not found

    问题描述 在 ubuntu1 16 04 10 执行 chkconfig 命令报 chkconfig command not found 说明此服务上没有安装 chkconfig 执行如下命令进行安装 span class token fu
  • Docker 基础篇 之 安装

    一 Docker安装 查看 CentOS 内核版本 Docker 要求 CentOS 系统的内核版本高于3 10 执行如下命令查询 内核版本 span class token function uname span r span class
  • Java 基础 之 Valid 验证

    一 64 Valid 简介 Bean Validation 内置的校验器 校验器说明 64 Null被注解的元素必须为 null 64 NotNull被注解的元素必须不为 null 64 AssertTrue被注解的元素必须为 true 6
  • HttpURLConnection链接详解

    HttpURLConnection链接详解 一 简介 简单来说 xff0c HttpURLConnection 是 Java 提供的发起 HTTP 请求的基础类库 xff0c 提供了 HTTP 请求的基本功能 xff0c 不过封装的比较少
  • Apache HttpClient 详解

    1 简介 HttpClient 是 Apache Jakarta Common 下的子项目 xff0c 用来提供高效的 最新的 功能丰富的支持 HTTP 协议的客户端编程工具包 xff0c 并且它支持 HTTP 协议最新的版本和建议 Htt