java处理http请求之Apache httpClient入门教程

说明

本文示例代码基于 4.5.13 版本

转载请注明出处:https://www.cnblogs.com/qnlcy/p/15378446.html

一、项目介绍

Apache 提供用来做http请求的项目有两个,3.x 版本的项目叫做 The Commons HttpClient

它一开始是 Apache Jakarta Common 下的子项目,后来独立出去了,现在这个项目已经结束了它的生命周期,不再开发和维护。

取而代之的是 4.x 版本的 Apache Httpcomponents 项目,它包括 HttpClientHttpCore 两大模块,能提供更好的性能和更大的灵活性。

二、项目模块

Apache Httpcomponents 项目包括 HttpClientHttpCore 两大模块,其中, HttpCore 是一套HTTP协议实现包。而 HttpClient 是基于HttpCore的一套客户端。

三、使用方式

使用 Httpclient 需要经过如下步骤

  1. 创建 HttpClient
  2. 创建 http 请求,如 HttpGetHttpPost
  3. 添加请求参数
  4. 添加请求设置,如超时等
  5. 使用 HttpClient 执行 http 请求
  6. 读取返回内容并释放连接

3.1 创建 HttpClient

3.1.1 创建默认客户端:

    CloseableHttpClient httpclient = HttpClients.createDefault();

一些重要的默认配置:

  • 默认连接池大小10,每域名最大连接5
  • 连接池中连接存活时间 connTimeToLive = -1 ,默认单位为毫秒,默认连接不失效
  • 域名验证器为 DefaultHostnameVerifier , 会验证域名
  • SSL 上下文为 SSLContext.getInstance("TLS"),没有使用密钥管理器(KeyManager)和信任管理器(TrustManager)

3.1.2 自定义客户端

  • 失败不重试
    CloseableHttpClient client = HttpClients.custom().setRetryHandler((e, i, c) -> false).build();
  • 自定义连接池
 //设置自定义连接池
    @Test
    public void customConnectionPool() throws Exception {
        //1.创建 https 需要的 SslContext 相关内容
        //1.1 创建 SslContext
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        ks.load(new FileInputStream("证书文件"), "密码".toCharArray());
        SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(TrustAllStrategy.INSTANCE)
                .loadKeyMaterial(ks, "证书密码".toCharArray()).build();
        //1.2 创建 SSLConnectionSocketFactory
        SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, new String[]{"SSLv3", "TLSv1.1", "TLSv1.2"}, null,
                NoopHostnameVerifier.INSTANCE);

        //2.创建连接池
        //2.1 构建协议 registry
        Registry registry = RegistryBuilder.create()
                .register("http", PlainConnectionSocketFactory.getSocketFactory())
                .register("https", sslConnectionSocketFactory)
                .build();
        PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(registry);
        //3.连接池针对所有连接、每域名的连接的数量设置
        poolingHttpClientConnectionManager.setMaxTotal(100);
        poolingHttpClientConnectionManager.setDefaultMaxPerRoute(20);

        //4.创建client
        CloseableHttpClient client =
        HttpClients.custom().setConnectionManager(poolingHttpClientConnectionManager).build();
    }

3.2 创建 Http 请求

创建 HttpGetHttpPost 请求

    @Test
    public void getAndPost(){
        //1.创建get请求
        HttpGet get = new HttpGet("https://www.baidu.com");

        //2.创建post请求
        HttpPost post = new HttpPost("https://www.baidu.com");

        //3.其他如 HttpPut、HttpOptions、HttpTrace、HttpDelete、HttpPatch
    }

3.3 添加请求参数

    @Test
    public void addParams() throws IOException {
        HttpPost post = new HttpPost("https://www.baidu.com");
        //1.底层流,基础参数
        BasicHttpEntity basicHttpEntity = new BasicHttpEntity();
        //1.1添加参数内容
        InputStream bis = new ByteArrayInputStream("参数".getBytes());
        basicHttpEntity.setContent(bis);
        //1.2设置内容长度
        basicHttpEntity.setContentLength(bis.available());
        //1.3取消分块发送
        basicHttpEntity.setChunked(false);
        post.setEntity(basicHttpEntity);

        //2.字节码类型参数
        HttpEntity entity = new ByteArrayEntity("name=zhangsan&age=100".getBytes());
        post.setEntity(entity);

        //3.字符串类型参数
        entity = new StringEntity("name=zhangsan&age=100");
        post.setEntity(entity);

        //4.流式参数,用法与BasicHttpEntity类似,内容和长度严格匹配
        entity = new InputStreamEntity(bis,bis.available());
        post.setEntity(entity);

        //5.文件类型参数
        entity = new FileEntity(new File("上传文件"));
        post.setEntity(entity);

        //6.添加请求头
        post.addHeader("Content-Type","text/html;charset=UTF-8");

        Header contentType = new BasicHeader("Content-Type","text/html;charset=UTF-8");
        post.addHeader(contentType);

        Header host = new BasicHeader("Host","www.baidu.com");
        post.setHeaders(new Header[]{contentType,host});

    }

3.4 添加请求设置

    @Test
    public void requestConfig(){
        //1.配置RequestConfig
        RequestConfig requestConfig = RequestConfig.custom()
        .setConnectionRequestTimeout(10000) //从连接池获取可用连接的超时时间,单位毫秒
        .setSocketTimeout(5000) //请求获取数据的超时时间
        .setConnectTimeout(4000) //连接超时时间
        .build();
        HttpPost post = new HttpPost("https://www.baidu.com");
        //2.设置到post请求当中
        post.setConfig(requestConfig);

        //也可以当作默认值,设置到client当中,此client都会按这个超时处理
        CloseableHttpClient client = HttpClients.custom().setDefaultRequestConfig(requestConfig).build();
    }

3.4.1 超时时间说明

超时类型 说明 connectionTimeout 连接建立时间,即3次握手时间,默认值-1 socketTimeout 连接后,数据传输过程中 数据包之间间隔

的最大时间,默认值-1 connectionRequestTimeout 从连接池获取连接的超时时间,默认值-1

java处理http请求之Apache httpClient入门教程

注意: socketTimeoutconnectionRequestTimeout 如果不设置,请求会阻塞。
但是 connectionTimeout 的情况有所不同,它依赖于各平台的 socket 超时时间设置。
windows 10 实测为 20s, linux 平台则不定,它会按 /proc/sys/net/ipv4/tcp_syn_retries 中配置的次数重试,一般为3s\7s\15s\31s\63s递增
另外,即使 java 程序返回了超时结果,但是linux服务器依旧在执行重试直到服务器端超时,为了提高资源利用率,可以手动关闭

关于 linux socket 超时的问题,请参阅 无毁的湖光-Al从linux源码看socket(tcp)的timeout

3.5 执行 http 请求

执行 http 请求比较简单,直接调用 execute() 方法即可

    @Test
    public void execute(){
        CloseableHttpClient client = HttpClients.createDefault();
        try {
            client.execute(new HttpPost("https://www.baidu.com"));
            client.execute(new HttpGet("https://www.baidu.com"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

3.6 读取返回内容并释放连接

服务器返回结果被封装到 HttpResponse 对象里,我们可以从这里拿到我们想要的返回结果

    @Test
    public void getResponse() {
        CloseableHttpClient client = HttpClients.createDefault();
        CloseableHttpResponse httpResponse = null;
        final HttpGet httpGet = new HttpGet("https://www.baidu.com");
        try {
            httpResponse = client.execute(httpGet);
            //1.获取返回状态
            System.out.println(httpResponse.getStatusLine().getStatusCode());
            //2.获取返回头信息
            Header[] headers = httpResponse.getAllHeaders();
            for (Header header : headers) {
                System.out.println(header.getName() + ":" + header.getValue());
            }
            //3.获取返回消息体
            HttpEntity entity = httpResponse.getEntity();
            if(null != entity){
                //3.1 得到返回结果并关闭流,与下面的只能执行一个,因为流只能读取一次
                String content = EntityUtils.toString(entity);
                System.out.println(content);
                //3.2 得到返回结果并关闭流,与上面的只能执行一个
//              byte[] contents = EntityUtils.toByteArray(entity);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != httpResponse) {
                //4.归还连接到连接池
                try {
                    httpResponse.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            //如果复用 httpGet ,则重置其状态使其可以重复使用
            httpGet.releaseConnection();
        }

        //只在应用关闭的时候关闭client
        try {
            client.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

Original: https://www.cnblogs.com/qnlcy/p/15378446.html
Author: 去哪里吃鱼
Title: java处理http请求之Apache httpClient入门教程

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/577906/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 解决 Docker Push Skipped foreign layer 的错误

    引言当Docker推送基于Windows镜像到私有仓库的时候会遇到 Skipped foreign layer的问题。 docker push 192.168.2.30:5000/…

    Linux 2023年6月14日
    0112
  • [转帖]bash shell学习之变量

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    Linux 2023年5月28日
    096
  • Question03-查询平均成绩大于等于60分的同学的学生编号和学生姓名和平均成绩

    * SELECT stu.SID, stu.Sname, CAST(AVG(sc.score) AS DECIMAL(18,2)) avg_score FROM Student s…

    Linux 2023年6月7日
    092
  • Java基础系列–08_集合1

    集合当中有很多都是应用到泛型的技术,所以在讲集合之前,应该先将泛型的概念普及一下。 泛型:(1)泛型是一种类型,但是这种类型是在编译或者调用方法时才确定。(2)格式: (3)好处:…

    Linux 2023年6月7日
    096
  • 维修数列代码及简易题解

    总体方案:将左右端点分别转到根和根的右儿子,将目标序列挤到以根的右儿子的左儿子为根的子树中,然后进行一系列骚操作即可 建树:用类似线段树的方法建树,递归即可,注意加两个边界点 插入…

    Linux 2023年6月6日
    0131
  • Centos7安装Redis

    下载 wget http://download.redis.io/releases/redis-5.0.0.tar.gz 解压 tar xvf redis-5.0.0.tar.gz…

    Linux 2023年5月28日
    099
  • redis 突然大量逐出导致读写请求block

    redis作为缓存场景使用,内存耗尽时,突然出现大量的逐出,在这个逐出的过程中阻塞正常的读写请求,导致 redis 短时间不可用; redis 中的LRU是如何实现的? 逐出qps…

    Linux 2023年5月28日
    093
  • 记一次burp suite文件上传漏洞实验

    一·文件上传漏洞概念文件上传漏洞是指 Web 服务器允许用户在没有充分验证文件名称、类型、内容或大小等内容的情况下将文件上传到其文件系统。未能正确执行这些限制可能意味着即使是基本的…

    Linux 2023年6月7日
    0109
  • CA证书介绍与格式转换

    PKCS 公钥加密标准(Public Key Cryptography Standards, PKCS),此一标准的设计与发布皆由RSA资讯安全公司(英语:RSA Security…

    Linux 2023年6月6日
    094
  • SQL52 获取employees中的first_name

    本题链接表结构如下所示(内容不完整):额外的要求是按照first_name最后两个字母升序进行输出。这里需要用到MySQL的字符串处理函数RIGHT。RIGHT函数的语法如下所示:…

    Linux 2023年6月13日
    0127
  • linux下中文输入法问题

    故事背景:最近在做资产上报相关功能,要支持中文输入,如果正常快捷方式启动程序没问题,但是升级或者卸载重新安装,自启的时候是使用su usr -C XX.sh启动,root下启动没办…

    Linux 2023年6月13日
    088
  • ELK收集日志之logstash使用

    一、logstash使用 1.logstah收集文件日志 不难理解,我们的日志通常都是在日志文件中存储的,所以,当我们在使用INPUT插件时,收集日志,需要使用file模块,从文件…

    Linux 2023年6月14日
    0119
  • Linux_shell基础

    注意, 这里在运行时一定要写成./test.sh,而不是 test.sh, 运行其它二进制的程序也一样,直接写 test.sh,Linux 系统会去 PATH(环境变量) 里寻找有…

    Linux 2023年5月27日
    0119
  • linux系统基于新磁盘和同磁盘其他分区的目录扩容

    linux系统基于新磁盘和同磁盘其他分区的目录扩容 (1) 基于新建磁盘目录扩容 例如:新增1 块3G 的磁盘sdb ,扩容/tmp 至13G pvcreate /dev/sdb1…

    Linux 2023年6月13日
    0108
  • 命令大全目录

    linux 本文来自博客园,作者:ivanlee717,转载请注明原文链接:https://www.cnblogs.com/ivanlee717/p/16341641.html O…

    Linux 2023年6月7日
    0147
  • shell脚本echo打印错位

    问题描述 在脚本中使用curl命令请求Jenkins的API获取job的编号,随后将编号和其他字符串拼接后,使用echo命令打印出来,但打印后字符串错位了。 脚本大致如下: num…

    Linux 2023年6月8日
    0126
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球