4.5日学习打卡----学习Apache HttpClient 5

这篇具有很好参考价值的文章主要介绍了4.5日学习打卡----学习Apache HttpClient 5。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

4.5日学习打卡

Apache Commons HttpClient

简介

Apache HttpClient 组件是为扩展而设计的,同时提供对基本HTTP协议的强大支持。

http://java.net包提供了通过HTTP访问资源的基本功能,但它并没有提供许多应用程序所需的全部灵活性或功能。HttpClient 组件通过提供一个高效、最新、功能丰富的包来填补这一空白,该包实现了最新HTTP标准的客户端。

HttpClient 过去是 Commons 的一部分,现在是 Apache HttpComponents 的一部分。Apache HttpComponents 是 Apache 的顶级项目,负责创建和维护专注于 HTTP 和相关协议的 Java 组件工具集。因此文章后面将不再使用 Commons HttpClient 字样,而是使用 HttpClient 。

HttpClient 目前有三个大版本,他们是不兼容的,可以同时存在。HttpClient 3过去是 Commons 的一部分,所以一般来说看到 Apache HttpClient 3的说法指的就是 Commons HttpClient,所属包 org.apache.commons.httpclient,maven 依赖如下

<!-- HttpClient 3 -->
<dependency>
    <groupId>commons-httpclient</groupId>
    <artifactId>commons-httpclient</artifactId>
    <version>3.1</version>
</dependency>

HttpClient 4 指的是 Apache HttpComponents 下的项目,所属包 org.apache.http,maven 依赖如下

<!-- HttpClient 4 -->
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.13</version>
</dependency>

HttpClient 5 指的是 Apache HttpComponents 下的最新项目,包结构是 org.apache.hc,依赖如下

<dependency>
    <groupId>org.apache.httpcomponents.client5</groupId>
    <artifactId>httpclient5</artifactId>
    <version>5.1</version>
</dependency>

HttpClient 3 早已不在维护,推荐使用最新的HttpClient 5。HttpClient 5 支持(经典API)(异步API)(反应式API)。

下面我将简单介绍下这几个版本 HttpClient 的用法。

  1. 原生API
    我们先来看看如果不使用 HttpClient 而是使用 Java 原生 API,写一个 http 请求的例子
package com.jjy.httpclient5demo.test;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

public class JavaApi {
    public static void main(String[] args) {
        HttpsURLConnection conn = null;
        try {
            URL url = new URL("https://httpbin.org/get");
            conn = (HttpsURLConnection) url.openConnection();
            // https请求需要设置证书,为了简单此处默认信任服务器不做证书校验
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, new TrustManager[]{new X509TrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
                }
                @Override
                public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
                }
                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return new X509Certificate[0];
                }
            }}, new java.security.SecureRandom());

            conn.setSSLSocketFactory(sc.getSocketFactory());
            conn.setHostnameVerifier((s, sslSession) -> true);
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(5000);
            conn.setUseCaches(false);
            conn.connect();
            InputStream is = conn.getInputStream();
            try (BufferedReader br = new BufferedReader(
                    new InputStreamReader(is))) {
                StringBuilder sb = new StringBuilder();
                String line;
                while ((line = br.readLine()) != null) {
                    sb.append(line).append("\n");
                }
                sb.deleteCharAt(sb.length() - 1);
                System.out.println(sb.toString());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (conn != null) {
                conn.disconnect();
            }
        }
    }
}

package com.jjy.httpclient5demo.test;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpHeaders;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

public class NativeJavaHttpClient {
    public static String get(String url) {
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .header("Accept", "application/json") // 如果需要的话,设置请求头
                .GET()
                .build();

        try {
            HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
            int statusCode = response.statusCode();
            System.out.println("Status Code: " + statusCode);
            System.out.println("Response Headers: " + response.headers());
            return response.body();
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static void main(String[] args) {
        String url = "http://httpbin.org/get";
        String responseContent = NativeJavaHttpClient.get(url);
        System.out.println(responseContent);
    }
}

我们看到这个例子是一个相对比较简单的 https 的 get请求,没有参数。代码已经比较复杂了,如果是 post 请求,需要传递参数,需要保存cookie(有些请求需求登录,我们还要先模拟登录请求后手动将 cookie 保存下来,下次请求在把 cookie 设置上)等场景代码将更为复杂。并且原生 API 默认不支持异步不支持响应式等,这时候就轮到 HttpClient 大显手身了。

  1. HttpClient 3
package com.jjy.httpclient5demo.test;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.GetMethod;

import java.io.IOException;

public class HttpClient3 {
    public static void main(String[] args) {
        // httpClient对象是线程安全的,可以单例使用,提升性能
        HttpClient httpClient = new HttpClient();
// 设置连接超时 和 socket超时
        httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(2000);
        httpClient.getHttpConnectionManager().getParams().setSoTimeout(5000); // 响应超时
        HttpMethod getM = new GetMethod("http://httpbin.org/get");
// 设置请求头
        getM.setRequestHeader("Content-Type", "application/json");
        NameValuePair p1 = new NameValuePair("name", "zs");
        NameValuePair p2 = new NameValuePair("age", "11");
// 设置查询参数,相当于 ?name=zs&age=11
        getM.setQueryString(new NameValuePair[]{p1, p2});
        try {
            int code = httpClient.executeMethod(getM);
            if (code == HttpStatus.SC_OK) {
                // 获取结果字符串
                String res = getM.getResponseBodyAsString();
                // InputStream res = getM.getResponseBodyAsStream(); // 也可以转换为流
                System.out.println(res);
            } else {
                System.err.println("请求失败,状态码:" + code);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 释放连接资源
            getM.releaseConnection();
        }
    }
}
  1. HttpClient 4
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.apache.http.client.utils.URIBuilder;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;

public class HttpClient4 {
    public static void main(String[] args) throws URISyntaxException {
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();

        // 创建一个URIBuilder来构建带参数的URL  
        URIBuilder uriBuilder = new URIBuilder("http://httpbin.org/get");
        try {
            // 添加参数  
            uriBuilder.addParameter("name", "zs");
            uriBuilder.addParameter("age", "11");

            // 构建最终的URI  
            URI uri = uriBuilder.build();

            HttpGet httpGet = new HttpGet(uri);

            // 设置请求配置(超时等)  
            RequestConfig requestConfig = RequestConfig.custom()
                    .setConnectTimeout(2000) // 连接超时  
                    .setConnectionRequestTimeout(2000) // 请求超时  
                    .setSocketTimeout(2000) // 响应超时  
                    .build();
            httpGet.setConfig(requestConfig);

            // 设置请求头(如果需要)  
            // httpGet.setHeader("Content-Type", "application/json"); // 注意:GET请求通常不需要Content-Type头  

            try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
                int statusCode = response.getStatusLine().getStatusCode();
                if (statusCode == HttpStatus.SC_OK) {
                    HttpEntity entity = response.getEntity();
                    System.out.println(EntityUtils.toString(entity, "UTF-8"));
                } else {
                    System.err.println("请求失败,状态码:" + statusCode);
                }
            } catch (IOException e) {
                System.err.println("请求异常:" + e.getMessage());
            }
        } catch (URISyntaxException e) {
            System.err.println("URI构建异常:" + e.getMessage());
        }
    }
}

Apache HttpClient 5

简介

Apache HttpClient 5 是一个开源的 HTTP 工具包,可以支持最新 HTTP 协议标准,且有丰富的 API 和强大的扩展特性,可以用于构建任何需要进行 HTTP 协议处理的应用程序。
下面将会介绍 Apache HttpClient 5 中最为常见的一些用法:
HttpClient 5 的 Get 请求、Post 请求、如何携带参数、JSON 参数、设置超时、异步请求、操作 Cookie、表单登录、基本认证、Digest 认证以及自定义 HTTP 请求拦截器等

依赖

maven

<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents.client5/httpclient5 -->
<dependency>
    <groupId>org.apache.httpcomponents.client5</groupId>
    <artifactId>httpclient5</artifactId>
    <version>5.1.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents.client5/httpclient5-fluent -->
<dependency>
    <groupId>org.apache.httpcomponents.client5</groupId>
    <artifactId>httpclient5-fluent</artifactId>
    <version>5.1.3</version>
</dependency>

HttpClient 5 GET 请求

package com.jjy.httpclient5demo.test;

import org.apache.hc.client5.http.classic.methods.HttpGet; // 导入Apache HttpClient 5的HttpGet类,用于发送HTTP GET请求  
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; // 导入CloseableHttpClient类,表示一个可关闭的HTTP客户端  
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; // 导入CloseableHttpResponse类,表示一个可关闭的HTTP响应  
import org.apache.hc.client5.http.impl.classic.HttpClients; // 导入HttpClients类,用于创建HttpClient实例  
import org.apache.hc.core5.http.HttpEntity; // 导入HttpEntity类,表示HTTP消息体  
import org.apache.hc.core5.http.ParseException; // 导入ParseException类,表示HTTP消息解析异常  
import org.apache.hc.core5.http.io.entity.EntityUtils; // 导入EntityUtils类,提供HTTP实体的工具方法  

// 注意:下面的导入似乎是不相关的,因为该类并不是一个Servlet  
// import javax.servlet.http.HttpServlet;  
// import javax.servlet.http.HttpServletRequest;  

import java.io.IOException; // 导入IO异常类  

public class GetHttp5Client {

    /**
     * 发送GET请求并返回响应内容  
     *
     * @param url 请求的URL  
     * @return 响应内容的字符串形式
     */
    public static String get(String url) {
        String resultContent = null; // 初始化响应内容的字符串为null  
        HttpGet httpGet = new HttpGet(url); // 创建HttpGet对象并设置请求的URL  
        try (CloseableHttpClient httpclient = HttpClients.createDefault()) { // 创建默认的CloseableHttpClient实例  
            try (CloseableHttpResponse response = httpclient.execute(httpGet)) { // 执行GET请求并获取响应  
                // 获取响应的状态信息  
                System.out.println(response.getVersion()); // 打印HTTP协议版本(例如:HTTP/1.1)  
                System.out.println(response.getCode()); // 打印响应的状态码(例如:200)  
                System.out.println(response.getReasonPhrase()); // 打印响应的状态描述(例如:OK)  
                HttpEntity entity = response.getEntity(); // 获取响应实体  
                // 将响应实体转换为字符串  
                resultContent = EntityUtils.toString(entity);
            }
        } catch (IOException | ParseException e) { // 捕获IO异常或HTTP消息解析异常  
            e.printStackTrace(); // 打印异常堆栈信息  
        }
        return resultContent; // 返回响应内容的字符串  
    }

    /**
     * 主函数,程序的入口点  
     *
     * @param args 命令行参数  
     */
    public static void main(String[] args) {
        // 测试GET请求,注意这里的URL已经被注释掉了,实际使用时可以取消注释并替换成需要的URL  
        // String url = "http://localhost:8080/user/loginwithcode";  
        // String url = "https://api.fastgpt.in/api/v1/chat/completions";  
        String url = "http://httpbin.org/get"; // 使用的测试URL  

        String s = GetHttp5Client.get(url); // 调用get方法发送GET请求并获取响应内容  
        System.out.println(s); // 打印响应内容  
    }
}

响应信息:

HTTP/1.1
200
OK
{
  "args": {}, 
  "headers": {
    "Accept-Encoding": "gzip, x-gzip, deflate", 
    "Host": "httpbin.org", 
    "User-Agent": "Apache-HttpClient/5.1.3 (Java/17)", 
    "X-Amzn-Trace-Id": "Root=1-62bb1891-5ab5e5376ed960471bf32f17"
  }, 
  "origin": "47.251.4.198", 
  "url": "http://httpbin.org/get"
}

HttpClient 5 Fluent GET

使用 Apache HttpClient 5 提供的 Fluent API 可以更便捷的发起 GET 请求,但是可操作的地方较少。

依赖:

<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents.client5/httpclient5-fluent -->
<dependency>
    <groupId>org.apache.httpcomponents.client5</groupId>
    <artifactId>httpclient5-fluent</artifactId>
    <version>5.1.3</version>
</dependency>

示例:

package com.jjy.httpclient5demo;

import java.io.IOException;

import org.apache.hc.client5.http.fluent.Request; // 导入Apache HttpClient 5的fluent API的Request类,用于构建HTTP请求  
import org.apache.hc.client5.http.fluent.Response; // 导入Apache HttpClient 5的fluent API的Response类,用于处理HTTP响应  

/**
 * 使用Apache HttpClient 5的fluent API发送GET请求并获取响应内容  
 *
 * @author zbxmx
 */
public class HttpClient5GetFluent {

    /**
     * 主函数,程序的入口点  
     *
     * @param args 命令行参数  
     */
    public static void main(String[] args) {
        // 调用get方法发送GET请求,并打印返回的响应内容  
        System.out.println(get("http://httpbin.org/get"));
    }

    /**
     * 发送GET请求并返回响应内容  
     *
     * @param url 请求的URL  
     * @return 响应内容的字符串形式
     */
    public static String get(String url) {
        String result = null; // 初始化响应内容的字符串为null  
        try {
            // 使用fluent API构建GET请求并执行,获取响应对象  
            Response response = Request.get(url).execute();
            // 从响应对象中获取响应内容,并转换为字符串  
            result = response.returnContent().asString();
        } catch (IOException e) {
            // 捕获IO异常,并打印异常堆栈信息  
            e.printStackTrace();
        }
        // 返回响应内容的字符串  
        return result;
    }

}

HttpClient5 GET 请求参数

使用 URIBuilder 的 addParameters() 方法来构建 GET 请求的参数。

package com.jjy.httpclient5demo.test;


import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;

import org.apache.hc.client5.http.classic.methods.HttpGet;
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.NameValuePair;
import org.apache.hc.core5.http.ParseException;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.message.BasicNameValuePair;
import org.apache.hc.core5.net.URIBuilder;

/**
 * 使用Apache HttpClient 5的经典API发送带有参数的GET请求并获取响应内容
 *
 * @author zbxmx
 */
public class HttpClient5GetParams {

    /**
     * 主函数,程序的入口点
     *
     * @param args 命令行参数
     */
    public static void main(String[] args) {
        // 调用get方法发送带有参数的GET请求,并打印返回的响应内容
        String result = get("http://httpbin.org/get");
        System.out.println(result);
    }

    /**
     * 发送带有参数的GET请求并返回响应内容
     *
     * @param url 请求的URL
     * @return 响应内容的字符串形式
     */
    public static String get(String url) {
        String resultContent = null;

        // 创建HttpGet对象,设置请求的URL
        HttpGet httpGet = new HttpGet(url);

        // 创建存放表单参数的列表
        List<NameValuePair> nvps = new ArrayList<>();

        // 添加GET请求参数
        nvps.add(new BasicNameValuePair("username", "wdbyte.com"));
        nvps.add(new BasicNameValuePair("password", "secret"));

        // 使用URIBuilder构建新的URI,将参数添加到请求URL中
        try {
            URI uri = new URIBuilder(new URI(url))
                    .addParameters(nvps) // 将参数添加到URL中
                    .build(); // 构建完整的URI

            // 设置HttpGet对象的URI
            httpGet.setUri(uri);
        } catch (URISyntaxException e) {
            // 如果URI构建出错,则抛出运行时异常
            throw new RuntimeException(e);
        }

        try (CloseableHttpClient httpclient = HttpClients.createDefault()) {
            // 创建默认的HttpClient实例
            try (CloseableHttpResponse response = httpclient.execute(httpGet)) {
                // 使用HttpClient执行GET请求,获取响应对象

                // 打印响应的HTTP版本、状态码和原因短语
                System.out.println(response.getVersion()); // HTTP/1.1
                System.out.println(response.getCode()); // 200
                System.out.println(response.getReasonPhrase()); // OK
                 
                HttpEntity entity = response.getEntity();

                // 将响应实体转换为字符串
                resultContent = EntityUtils.toString(entity);
            }
        } catch (IOException | ParseException e) {
            // 捕获IO异常或解析异常,并打印异常堆栈信息
            e.printStackTrace();
        }

        // 返回响应内容的字符串
        return resultContent;
    }
}

输出信息:

{
  "args": {
    "password": "secret", 
    "username": "wdbyte.com"
  }, 
  "headers": {
    "Accept-Encoding": "gzip, x-gzip, deflate", 
    "Host": "httpbin.org", 
    "User-Agent": "Apache-HttpClient/5.1.3 (Java/1.8.0_151)", 
    "X-Amzn-Trace-Id": "Root=1-62ecc660-69d58a226aefb1b6226541ec"
  }, 
  "origin": "218.26.154.94", 
  "url": "http://httpbin.org/get?username=wdbyte.com&password=secret"
}

HttpClient 5 POST 请求

下面演示发起一个 POST 请求,并携带表单参数。

package com.jjy.httpclient5demo.test;


import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

import org.apache.hc.client5.http.classic.methods.HttpPost;
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.NameValuePair;
import org.apache.hc.core5.http.ParseException;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.message.BasicNameValuePair;
/**
 * 使用Apache HttpClient 5的经典API发送带有表单参数的POST请求并获取响应内容
 *
 * @author zbxmx
 */
public class HttpClient5Post {

    /**
     * 主函数,程序的入口点
     *
     * @param args 命令行参数
     */
    public static void main(String[] args) {
        // 调用post方法发送带有表单参数的POST请求,并打印返回的响应内容
        String result = post("http://httpbin.org/post");
        System.out.println(result);
    }

    /**
     * 发送带有表单参数的POST请求并返回响应内容
     *
     * @param url 请求的URL
     * @return 响应内容的字符串形式
     */
    public static String post(String url) {
        String result = null;

        // 创建HttpPost对象,设置请求的URL
        HttpPost httpPost = new HttpPost(url);

        // 创建存放表单参数的列表
        List<NameValuePair> nvps = new ArrayList<>();

        // 添加POST请求参数
        nvps.add(new BasicNameValuePair("username", "wdbyte.com"));
        nvps.add(new BasicNameValuePair("password", "secret"));

        // 创建UrlEncodedFormEntity,将表单参数添加到POST请求中
        httpPost.setEntity(new UrlEncodedFormEntity(nvps));


        try (CloseableHttpClient httpclient = HttpClients.createDefault()) {
            // 创建默认的HttpClient实例
            try (CloseableHttpResponse response = httpclient.execute(httpPost)) {
                // 使用HttpClient执行POST请求,获取响应对象

                // 打印响应的HTTP版本、状态码和原因短语
                System.out.println(response.getVersion()); // HTTP/1.1
                System.out.println(response.getCode()); // 200
                System.out.println(response.getReasonPhrase()); // OK

                // 获取响应实体
                HttpEntity entity = response.getEntity();

                // 将响应实体转换为字符串
                result = EntityUtils.toString(entity);

                // 确保响应实体被完全消费,避免资源泄露
                EntityUtils.consume(entity);
            }
        } catch (IOException | ParseException e) {
            // 捕获IO异常,并打印异常堆栈信息
            e.printStackTrace();
        }

        // 返回响应内容的字符串
        return result;
    }
}

输出结果:

{
  "args": {}, 
  "data": "", 
  "files": {}, 
  "form": {
    "password": "secret", 
    "username": "wdbyte.com"
  }, 
  "headers": {
    "Accept-Encoding": "gzip, x-gzip, deflate", 
    "Content-Length": "35", 
    "Content-Type": "application/x-www-form-urlencoded; charset=ISO-8859-1", 
    "Host": "httpbin.org", 
    "User-Agent": "Apache-HttpClient/5.1.3 (Java/17.0.9)", 
    "X-Amzn-Trace-Id": "Root=1-660fe4f3-76d02ec05aa7a6535e833aad"
  }, 
  "json": null, 
  "origin": "218.26.154.94", 
  "url": "http://httpbin.org/post"
}

HttpClient 5 Fluent POST

使用 Apache HttpClient 5 提供的 Fluent API 可以更便捷的发起 POST 请求,但是可操作的地方较少。

package com.jjy.httpclient5demo.test;

import java.io.IOException;

import org.apache.hc.client5.http.fluent.Request;
import org.apache.hc.core5.http.message.BasicNameValuePair;

/**
 * @author zbzmx
 */
public class HttpClient5PostFluent {

    public static void main(String[] args) {
        String result = post("http://httpbin.org/post");
        System.out.println(result);
    }

    public static String post(String url) {
        String result = null;
        Request request = Request.post(url);
        // POST 请求参数
        request.bodyForm(
                new BasicNameValuePair("username", "wdbyte.com"),
                new BasicNameValuePair("password", "secret"));
        try {
            result = request.execute().returnContent().asString();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }
}

HttpClient5 POST JSON 参数

package com.jjy.httpclient5demo.test;



import java.io.IOException;

import org.apache.hc.client5.http.classic.methods.HttpPost;
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.ContentType;
import org.apache.hc.core5.http.ParseException;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.io.entity.StringEntity;

/**
 * @author zbxmx
 */
public class HttpClient5PostWithJson {

    public static void main(String[] args) {
        String json = "{"
                + "    \"password\": \"secret\","
                + "    \"username\": \"wdbyte.com\""
                + "}";
        String result = post("http://httpbin.org/post", json);
        System.out.println(result);
    }

    public static String post(String url, String jsonBody) {
        String result = null;
        HttpPost httpPost = new HttpPost(url);
        httpPost.setEntity(new StringEntity(jsonBody, ContentType.APPLICATION_JSON));

        try (CloseableHttpClient httpclient = HttpClients.createDefault()) {
            try (CloseableHttpResponse response = httpclient.execute(httpPost)) {
                // 获取响应信息
                result = EntityUtils.toString(response.getEntity());
            }
        } catch (IOException | ParseException e) {
            e.printStackTrace();
        }
        return result;
    }

}

输出结果:

{
  "args": {}, 
  "data": "{    \"password\": \"secret\",    \"username\": \"wdbyte.com\"}", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Accept-Encoding": "gzip, x-gzip, deflate", 
    "Content-Length": "55", 
    "Content-Type": "application/json; charset=UTF-8", 
    "Host": "httpbin.org", 
    "User-Agent": "Apache-HttpClient/5.1.3 (Java/17.0.9)", 
    "X-Amzn-Trace-Id": "Root=1-660ff565-0afd9ffd3d41ed4417652ca1"
  }, 
  "json": {
    "password": "secret", 
    "username": "wdbyte.com"
  }, 
  "origin": "218.26.154.94", 
  "url": "http://httpbin.org/post"
}

HttpClient 5 设置超时

使用 RequestConfig 对象来配置超时时间。

package com.jjy.httpclient5demo.test;


import java.io.IOException;

import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.config.RequestConfig;
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.ParseException;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.util.Timeout;

/**
 * @author zbxmx
 */
public class HttpClient5GetWithTimeout {

    public static void main(String[] args) {
        String result = get("http://httpbin.org/get");
        System.out.println(result);
    }

    public static String get(String url) {
        String resultContent = null;
        // 设置超时时间
        RequestConfig config = RequestConfig.custom()
                .setConnectTimeout(Timeout.ofMilliseconds(5000L))
                .setConnectionRequestTimeout(Timeout.ofMilliseconds(5000L))
                .setResponseTimeout(Timeout.ofMilliseconds(5000L))
                .build();
        // 请求级别的超时
        HttpGet httpGet = new HttpGet(url);
        //httpGet.setConfig(config);
        //try (CloseableHttpClient httpclient = HttpClients.createDefault()) {
        // 客户端级别的超时
        try (CloseableHttpClient httpclient = HttpClients.custom().setDefaultRequestConfig(config).build()) {
            try (CloseableHttpResponse response = httpclient.execute(httpGet)) {
                // 获取状态码
                System.out.println(response.getVersion()); // HTTP/1.1
                System.out.println(response.getCode()); // 200
                System.out.println(response.getReasonPhrase()); // OK
                HttpEntity entity = response.getEntity();
                // 获取响应信息
                resultContent = EntityUtils.toString(entity);
            }
        } catch (IOException | ParseException e) {
            e.printStackTrace();
        }
        return resultContent;
    }

}

HttpClient 5 异步请求

下面演示三种 HttpClient 5 异步请求方式。

package com.jjy.httpclient5demo.test;

import java.io.IOException;
import java.nio.CharBuffer;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

import org.apache.hc.client5.http.async.methods.AbstractCharResponseConsumer;
import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
import org.apache.hc.client5.http.async.methods.SimpleHttpRequests;
import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
import org.apache.hc.core5.concurrent.FutureCallback;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.HttpException;
import org.apache.hc.core5.http.HttpResponse;
import org.apache.hc.core5.http.nio.AsyncRequestProducer;
import org.apache.hc.core5.http.nio.support.AsyncRequestBuilder;

/**
 * HttpClient 5 异步请求
 * @author https://www.wdbyte.com
 *
 */
public class HttpClient5Async {

    public static void main(String[] args) {
        getAsync1("http://httpbin.org/get");
        getAsync2("http://httpbin.org/get");
        getAsync3("http://httpbin.org/get");
    }

    /**
     * 异步请求
     *
     * @param url
     * @return
     */
    public static String getAsync1(String url) {
        try (CloseableHttpAsyncClient httpclient = HttpAsyncClients.createDefault()) {
            // 开始 http clinet
            httpclient.start();
            // 执行请求
            SimpleHttpRequest request1 = SimpleHttpRequests.get(url);
            Future<SimpleHttpResponse> future = httpclient.execute(request1, null);
            // 等待直到返回完毕
            SimpleHttpResponse response1 = future.get();
            System.out.println("getAsync1:" + request1.getRequestUri() + "->" + response1.getCode());
        } catch (IOException | ExecutionException | InterruptedException e) {
            throw new RuntimeException(e);
        }
        return null;
    }

    /**
     * 异步请求,根据响应情况回调
     *
     * @param url
     * @return
     */
    public static String getAsync2(String url) {
        try (CloseableHttpAsyncClient httpclient = HttpAsyncClients.createDefault()) {
            // 开始 http clinet
            httpclient.start();
            // 根据请求响应情况进行回调操作
            CountDownLatch latch = new CountDownLatch(1);
            SimpleHttpRequest request = SimpleHttpRequests.get(url);
            httpclient.execute(request, new FutureCallback<SimpleHttpResponse>() {
                @Override
                public void completed(SimpleHttpResponse response2) {
                    latch.countDown();
                    System.out.println("getAsync2:" + request.getRequestUri() + "->" + response2.getCode());
                }

                @Override
                public void failed(Exception ex) {
                    latch.countDown();
                    System.out.println("getAsync2:" + request.getRequestUri() + "->" + ex);
                }

                @Override
                public void cancelled() {
                    latch.countDown();
                    System.out.println("getAsync2:" + request.getRequestUri() + " cancelled");
                }

            });
            latch.await();
        } catch (IOException | InterruptedException e) {
            throw new RuntimeException(e);
        }
        return null;
    }

    /**
     * 异步请求,对响应流做点什么
     *
     * @param url
     * @return
     */
    public static String getAsync3(String url) {
        try (CloseableHttpAsyncClient httpclient = HttpAsyncClients.createDefault()) {
            // 开始 http clinet
            httpclient.start();
            // 根据请求响应情况进行回调操作
            SimpleHttpRequest request = SimpleHttpRequests.get(url);

            CountDownLatch latch = new CountDownLatch(1);
            AsyncRequestProducer producer = AsyncRequestBuilder.get("http://httpbin.org/get").build();
            AbstractCharResponseConsumer<HttpResponse> consumer3 = new AbstractCharResponseConsumer<HttpResponse>() {

                HttpResponse response;

                @Override
                protected void start(HttpResponse response, ContentType contentType) throws HttpException, IOException {
                    System.out.println("getAsync3: 开始响应....");
                    this.response = response;
                }

                @Override
                protected int capacityIncrement() {
                    return Integer.MAX_VALUE;
                }

                @Override
                protected void data(CharBuffer data, boolean endOfStream) throws IOException {
                    System.out.println("getAsync3: 收到数据....");
                    // Do something useful
                }

                @Override
                protected HttpResponse buildResult() throws IOException {
                    System.out.println("getAsync3: 接收完毕...");
                    return response;
                }

                @Override
                public void releaseResources() {
                }

            };
            httpclient.execute(producer, consumer3, new FutureCallback<HttpResponse>() {

                @Override
                public void completed(HttpResponse response) {
                    latch.countDown();
                    System.out.println("getAsync3: "+request.getRequestUri() + "->" + response.getCode());
                }

                @Override
                public void failed(Exception ex) {
                    latch.countDown();
                    System.out.println("getAsync3: "+request.getRequestUri() + "->" + ex);
                }

                @Override
                public void cancelled() {
                    latch.countDown();
                    System.out.println("getAsync3: "+request.getRequestUri() + " cancelled");
                }

            });
            latch.await();
        } catch (IOException | InterruptedException e) {
            throw new RuntimeException(e);
        }
        return null;

    }
}

输出结果

getAsync1:/get->200
getAsync2:/get->200
getAsync3: 开始响应....
getAsync3: 收到数据....
getAsync3: 收到数据....
getAsync3: 收到数据....
getAsync3: 接收完毕...
getAsync3: /get->200

HttpClient 5 获取 Cookie

请求 http://httpbin.org/cookies/set/cookieName/www.wdbyte.com 的响应中会带有一个Cookie 信息,其中 name 为 cookieName,value 为 www.wdbyte.com,我们以此用作测试。

package com.jjy.httpclient5demo.test;

import java.util.List;

import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.cookie.BasicCookieStore;
import org.apache.hc.client5.http.cookie.Cookie;
import org.apache.hc.client5.http.cookie.CookieStore;
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.client5.http.impl.cookie.BasicClientCookie;
import org.apache.hc.client5.http.protocol.HttpClientContext;
import org.apache.hc.core5.http.io.entity.EntityUtils;

/**
 * 这个例子演示了使用本地HTTP上下文填充, 自定义属性
 */
public class HttpClient5WithCookie {

    public static void main(final String[] args) throws Exception {
        try (final CloseableHttpClient httpclient = HttpClients.createDefault()) {
            // 创建一个本地的 Cookie 存储
            final CookieStore cookieStore = new BasicCookieStore();
            // BasicClientCookie clientCookie = new BasicClientCookie("name", "www.wdbyte.com");
            // clientCookie.setDomain("http://httpbin.org/cookies");
            // 过期时间
            // clientCookie.setExpiryDate(new Date());
            // 添加到本地 Cookie
            // cookieStore.addCookie(clientCookie);

            // 创建本地 HTTP 请求上下文 HttpClientContext
            final HttpClientContext localContext = HttpClientContext.create();
            // 绑定 cookieStore 到 localContext
            localContext.setCookieStore(cookieStore);

            final HttpGet httpget = new HttpGet("http://httpbin.org/cookies/set/cookieName/www.wdbyte.com");
            System.out.println("执行请求 " + httpget.getMethod() + " " + httpget.getUri());

            // 获取 Coolie 信息
            try (final CloseableHttpResponse response = httpclient.execute(httpget, localContext)) {
                System.out.println("----------------------------------------");
                System.out.println(response.getCode() + " " + response.getReasonPhrase());
                final List<Cookie> cookies = cookieStore.getCookies();
                for (int i = 0; i < cookies.size(); i++) {
                    System.out.println("Local cookie: " + cookies.get(i));
                }
                EntityUtils.consume(response.getEntity());
            }
        }
    }

}

输出结果:

执行请求 GET http://httpbin.org/cookies/set/cookieName/www.wdbyte.com
----------------------------------------
200 OK
Local cookie: [name: cookieName; value: www.wdbyte.com; domain: httpbin.org; path: /; expiry: null]

HttpClient 5 读取文件内容请求

准备一个 JSON 内容格式的文件 params.json。

{"name":"www.wdbyte.com"}

读取这个文件作为请求参数发起请求。

package com.jjy.httpclient5demo.test;


import java.io.File;
import java.io.FileInputStream;

import org.apache.hc.client5.http.classic.methods.HttpPost;
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.ContentType;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.io.entity.FileEntity;
import org.apache.hc.core5.http.io.entity.InputStreamEntity;

/**
 * 加载数据流作为 POST 请求参数
 */
public class HttpClient5ChunkEncodedPost {

    public static void main(final String[] args) throws Exception {
        String params = "/Users/darcy/params.json";

        try (final CloseableHttpClient httpclient = HttpClients.createDefault()) {
            final HttpPost httppost = new HttpPost("http://httpbin.org/post");

            final InputStreamEntity reqEntity = new InputStreamEntity(new FileInputStream(params), -1,
                    ContentType.APPLICATION_JSON);
            // 也可以使用 FileEntity 的形式
            // FileEntity reqEntity = new FileEntity(new File(params), ContentType.APPLICATION_JSON);

            httppost.setEntity(reqEntity);

            System.out.println("执行请求 " + httppost.getMethod() + " " + httppost.getUri());
            try (final CloseableHttpResponse response = httpclient.execute(httppost)) {
                System.out.println("----------------------------------------");
                System.out.println(response.getCode() + " " + response.getReasonPhrase());
                System.out.println(EntityUtils.toString(response.getEntity()));
            }
        }
    }
}

输出结果

执行请求 POST http://httpbin.org/post
----------------------------------------
200 OK
{
  "args": {}, 
  "data": "{\"name\":\"www.wdbyte.com\"}\n", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Accept-Encoding": "gzip, x-gzip, deflate", 
    "Content-Length": "26", 
    "Content-Type": "application/json; charset=UTF-8", 
    "Host": "httpbin.org", 
    "User-Agent": "Apache-HttpClient/5.1.3 (Java/1.8.0_151)", 
    "X-Amzn-Trace-Id": "Root=1-62ee4d95-1f956d4303cea09c52694c86"
  }, 
  "json": {
    "name": "www.wdbyte.com"
  }, 
  "origin": "42.120.74.238", 
  "url": "http://httpbin.org/post"
}

HttpClient 5 表单登录

表单登录可以理解为发起一个携带了认证信息的请求,然后得到响应的 Cookie 的过程。当然这里不仅仅适用于表单登录,也可以是简单的发起一个携带了表单信息的请求。

本应该使用 POST 请求发送表单参数测试,但是在 httpbin.org 中没有对应的接口用于测试,所以这里换成了 GET 请求


package com.jjy.httpclient5demo.test;



import java.util.ArrayList;
import java.util.List;

import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.cookie.BasicCookieStore;
import org.apache.hc.client5.http.cookie.Cookie;
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.NameValuePair;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.message.BasicNameValuePair;

/**
 * 演示基于表单的登录
 *
 * @author zbxmx
 */
public class HttpClient5FormLogin {

    public static void main(final String[] args) throws Exception {
        final BasicCookieStore cookieStore = new BasicCookieStore();
        try (final CloseableHttpClient httpclient = HttpClients.custom()
                .setDefaultCookieStore(cookieStore)
                .build()) {

            // 本应该使用 POST 请求发送表单参数,但是在 httpbin.org 中没有对应的接口用于测试,所以这里换成了 GET 请求
            // HttpPost httpPost = new HttpPost("http://httpbin.org/cookies/set/username/wdbyte.com");
            HttpGet httpPost = new HttpGet("http://httpbin.org/cookies/set/username/wdbyte.com");
            // POST 表单请求参数
            List<NameValuePair> nvps = new ArrayList<>();
            nvps.add(new BasicNameValuePair("username", "wdbyte.com"));
            nvps.add(new BasicNameValuePair("password", "secret"));
            httpPost.setEntity(new UrlEncodedFormEntity(nvps));

            try (final CloseableHttpResponse response2 = httpclient.execute(httpPost)) {
                final HttpEntity entity = response2.getEntity();

                System.out.println("Login form get: " + response2.getCode() + " " + response2.getReasonPhrase());
                System.out.println("当前响应信息 "+EntityUtils.toString(entity));;

                System.out.println("Post 登录 Cookie:");
                final List<Cookie> cookies = cookieStore.getCookies();
                if (cookies.isEmpty()) {
                    System.out.println("None");
                } else {
                    for (int i = 0; i < cookies.size(); i++) {
                        System.out.println("- " + cookies.get(i));
                    }
                }
            }
        }
    }
}

输出结果:


Login form get: 200 OK
当前响应信息 {
  "cookies": {
    "username": "wdbyte.com"
  }
}
 
Post 登录 Cookie:
- [name: username; value: wdbyte.com; domain: httpbin.org; path: /; expiry: null]

HttpClient 5 Basic Authorization

HTTP 基本认证(Basic Authorization)是一种比较简单的认证实现,主要流程如下

  1. 请求一个需要进行基本认证的 HTTP 接口,但是没有携带认证信息。

  2. 此时会响应 401 状态码,并在响应 header 中的 WWW-Authenticate 提示需要进行基本认证。

  3. 用户把需要提交认证信息进行冒号拼接,然后进行 base64 编码,再在得到的字符串开头拼接上 Basic 放入请求头 Authorization 中。

  4. 认证成功,响应成功。

你可以通过浏览器打开下面这个 URL 进行基本认证测试。

http://httpbin.org/basic-auth/admin/123456


package com.jjy.httpclient5demo.test;


import org.apache.hc.client5.http.auth.AuthScope;
import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
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.io.entity.EntityUtils;

/**
 * 一个简单的示例,它使用HttpClient执行HTTP请求;
 * 一个需要进行用户身份验证的目标站点。
 */
public class HttpClient5BasicAuthentication {

    public static void main(final String[] args) throws Exception {
        final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
        credsProvider.setCredentials(
                new AuthScope("httpbin.org", 80),
                new UsernamePasswordCredentials("admin", "123456".toCharArray()));
        try (final CloseableHttpClient httpclient = HttpClients.custom()
                .setDefaultCredentialsProvider(credsProvider)
                .build()) {
            final HttpGet httpget = new HttpGet("http://httpbin.org/basic-auth/admin/123456");

            System.out.println("执行请求" + httpget.getMethod() + " " + httpget.getUri());
            try (final CloseableHttpResponse response = httpclient.execute(httpget)) {
                System.out.println("----------------------------------------");
                System.out.println(response.getCode() + " " + response.getReasonPhrase());
                System.out.println(EntityUtils.toString(response.getEntity()));
            }
        }
    }
}

输出结果

执行请求GET http://httpbin.org/basic-auth/user/passwd
----------------------------------------
200 OK
{
  "authenticated": true, 
  "user": "user"
}

HttpClient 5 Digest Authorization

HTTP Basic Authorization 的缺点显而易见,密码通过明文传输存在一定的安全风险,Digest Authorization 认证方式解决了明文传输的问题,这里不过多介绍 Digest 的相关内容,通过一个图简单的示意 Digest 认证方式的流程。

package com.jjy.httpclient5demo.test;


import org.apache.hc.client5.http.auth.AuthExchange;
import org.apache.hc.client5.http.auth.AuthScheme;
import org.apache.hc.client5.http.auth.AuthScope;
import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
import org.apache.hc.client5.http.impl.auth.DigestScheme;
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.client5.http.protocol.HttpClientContext;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.io.entity.EntityUtils;

/**
 *
 * HttpClient如何验证多个请求的示例
 * 使用相同的摘要方案。在初始请求/响应交换之后
 * 共享相同执行上下文的所有后续请求都可以重用
 * 要向服务器进行身份验证的最后一个摘要nonce值。
 */
public class HttpClient5PreemptiveDigestAuthentication {

    public static void main(final String[] args) throws Exception {
        try (final CloseableHttpClient httpclient = HttpClients.createDefault()) {

            final HttpHost target = new HttpHost("http", "httpbin.org", 80);

            final HttpClientContext localContext = HttpClientContext.create();
            final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
            credentialsProvider.setCredentials(
                    new AuthScope(target),
                    new UsernamePasswordCredentials("admin", "123456".toCharArray()));
            localContext.setCredentialsProvider(credentialsProvider);

            final HttpGet httpget = new HttpGet("http://httpbin.org/digest-auth/auth/admin/123456");

            System.out.println("执行请求 " + httpget.getMethod() + " " + httpget.getUri());
            for (int i = 0; i < 2; i++) {
                try (final CloseableHttpResponse response = httpclient.execute(target, httpget, localContext)) {
                    System.out.println("----------------------------------------");
                    System.out.println(response.getCode() + " " + response.getReasonPhrase());
                    EntityUtils.consume(response.getEntity());

                    final AuthExchange authExchange = localContext.getAuthExchange(target);
                    if (authExchange != null) {
                        final AuthScheme authScheme = authExchange.getAuthScheme();
                        if (authScheme instanceof DigestScheme) {
                            final DigestScheme digestScheme = (DigestScheme) authScheme;
                            System.out.println("Nonce: " + digestScheme.getNonce() +
                                    "; count: " + digestScheme.getNounceCount());
                        }
                    }
                }
            }
        }
    }

}

HttpClient 5 拦截器

HttpClient 5 中的拦截器可以对请求过程的各个阶段进行拦截处理,通过 HttpClientBuilder 中的关于 Interceptor 的方法可以看到可以

HttpClient5 拦截器

下面编写一个示例,发起三次请求,每次请求都在请求头 herader 中增加一个 request-id 参数,然后对 request-id 值为 2 的请求直接响应 404 结束。

package com.jjy.httpclient5demo.test;


import java.io.IOException;
import java.util.concurrent.atomic.AtomicLong;

import org.apache.hc.client5.http.classic.ExecChain;
import org.apache.hc.client5.http.classic.ExecChain.Scope;
import org.apache.hc.client5.http.classic.ExecChainHandler;
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.impl.ChainElement;
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.ClassicHttpRequest;
import org.apache.hc.core5.http.ClassicHttpResponse;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.EntityDetails;
import org.apache.hc.core5.http.Header;
import org.apache.hc.core5.http.HttpEntity;
import org.apache.hc.core5.http.HttpException;
import org.apache.hc.core5.http.HttpRequest;
import org.apache.hc.core5.http.HttpRequestInterceptor;
import org.apache.hc.core5.http.HttpStatus;
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.BasicClassicHttpResponse;
import org.apache.hc.core5.http.protocol.HttpContext;

/**
 * 展示如何在请求和响应时进行拦截进行自定义处理。
 */
public class HttpClient5Interceptors {

    public static void main(final String[] args) throws Exception {
        try (final CloseableHttpClient httpclient = HttpClients.custom()
                // 添加一个请求 id 到请求 header
                .addRequestInterceptorFirst(new HttpRequestInterceptor() {
                    private final AtomicLong count = new AtomicLong(0);
                    @Override
                    public void process(
                            final HttpRequest request,
                            final EntityDetails entity,
                            final HttpContext context) throws HttpException, IOException {
                        request.setHeader("request-id", Long.toString(count.incrementAndGet()));
                    }
                })
                .addExecInterceptorAfter(ChainElement.PROTOCOL.name(), "custom", new ExecChainHandler() {
                    // 请求 id 为 2 的,模拟 404 响应,并自定义响应的内容。
                    @Override
                    public ClassicHttpResponse execute(
                            final ClassicHttpRequest request,
                            final Scope scope,
                            final ExecChain chain) throws IOException, HttpException {

                        final Header idHeader = request.getFirstHeader("request-id");
                        if (idHeader != null && "2".equalsIgnoreCase(idHeader.getValue())) {
                            final ClassicHttpResponse response = new BasicClassicHttpResponse(HttpStatus.SC_NOT_FOUND,
                                    "Oppsie");
                            response.setEntity(new StringEntity("bad luck", ContentType.TEXT_PLAIN));
                            return response;
                        } else {
                            return chain.proceed(request, scope);
                        }
                    }
                })
                .build()) {

            for (int i = 0; i < 3; i++) {
                final HttpGet httpget = new HttpGet("http://httpbin.org/get");

                try (final CloseableHttpResponse response = httpclient.execute(httpget)) {
                    System.out.println("----------------------------------------");
                    System.out.println("执行请求 " + httpget.getMethod() + " " + httpget.getUri());
                    System.out.println(response.getCode() + " " + response.getReasonPhrase());
                    System.out.println(EntityUtils.toString(response.getEntity()));
                }
            }
        }
    }

}

输出结果

----------------------------------------
执行请求 GET http://httpbin.org/get
200 OK
{
  "args": {}, 
  "headers": {
    "Accept-Encoding": "gzip, x-gzip, deflate", 
    "Host": "httpbin.org", 
    "Request-Id": "1", 
    "User-Agent": "Apache-HttpClient/5.1.3 (Java/1.8.0_151)", 
    "X-Amzn-Trace-Id": "Root=1-62f615ba-658ccd42182d22534dbba82c"
  }, 
  "origin": "42.120.75.221", 
  "url": "http://httpbin.org/get"
}
 
----------------------------------------
执行请求 GET http://httpbin.org/get
404 Oppsie
bad luck
----------------------------------------
执行请求 GET http://httpbin.org/get
200 OK
{
  "args": {}, 
  "headers": {
    "Accept-Encoding": "gzip, x-gzip, deflate", 
    "Host": "httpbin.org", 
    "Request-Id": "3", 
    "User-Agent": "Apache-HttpClient/5.1.3 (Java/1.8.0_151)", 
    "X-Amzn-Trace-Id": "Root=1-62f615bb-4eb6ba10736ace0e21d0cb8c"
  }, 
  "origin": "42.120.75.221", 
  "url": "http://httpbin.org/get"
}

如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力
apache httpclient5,每日学习,学习,apache文章来源地址https://www.toymoban.com/news/detail-848211.html

到了这里,关于4.5日学习打卡----学习Apache HttpClient 5的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Java万花筒】解码Java网络通讯谜团:对比Apache HttpClient、OkHttp、Feign、RestTemplate、Retrofit

    在当今互联网时代,Java开发者常常需要处理与各种RESTful服务的通信。本文旨在深入比较Java中几个主流的网络请求库,包括Apache HttpClient、OkHttp、Feign、RestTemplate、Retrofit。通过全面的介绍和示例代码,读者将能够了解它们的特点、优势以及如何在实际项目中使用。 欢迎订阅专

    2024年01月25日
    浏览(46)
  • 【Spring Cloud】如何把Feign默认的HTTP客户端URLConnection更换成支持连接池的Apache HttpClient或OKHttp

    本次示例代码的文件结构如下图所示。 Feign 发送 HTTP 请求时,底层会使用到别的客户端。下面列出常用的 3 种 HTTP 客户端。 HTTP客户端 特点 URLConnection Feign 的默认实现,不支持连接池 Apache HttpClient 支持连接池 OKHttp 支持连接池 其中, URLConnection 是 Feign 默认使用的 HTTP 客户端

    2024年02月14日
    浏览(52)
  • Apache Kafka学习

    目录 一、简介 1.概念: 2.kafka四大API: 3.Kafka消费模式 4.Kafka的基础架构 5.kafka文件存储方式 二、特性 三、优点 1.解耦 2.异步处理 3.流量削峰 4.数据持久化 5.顺序保证 6.可恢复性 四、名词解释 五、QA Q:如何保证数据高可靠、不丢失? A:数据丢失的原因 解决方案 producer 生产消

    2024年02月09日
    浏览(39)
  • Apache Kudu入门学习

    目录 一、概念 二、背景 三、特点 四、架构 五、应用场景 六、kudu的模式设计 1、列设计 2、主键设计 3、分区设计 1.范围分区Range Partitioning  2.哈希分区Hash Partitioning 3.多级分区Multilevel Partitioning 官方概念: Apache Kudu is an open source distributed data storage engine that makes fast analytics

    2024年02月08日
    浏览(32)
  • Apache Doris 学习笔记

    目录 一、Doris简介 一)概述 二)使用场景 三)架构 二、Doris安装部署 一)安装要求 2.1.1 Linux操作系统 2.1.2 软件需求 2.1.3 开发测试环境 2.1.4 生产环境 2.1.5 内部端口使用说明 二)部署 2.2.1 操作系统 2.2.2 Doris安装包 2.2.3 解压安装包 2.2.4 配置FE 2.2.5 配置BE 三、Doris数据表设计

    2024年02月05日
    浏览(35)
  • Apache Zeppelin学习记录2

    上一章讲了如何使用zeppelin来接入python,本节我们来看看如何使用RESTful API操作zeppelin的paragraph。 提示:官方API文档见 https://zeppelin.apache.org/docs/0.10.1/usage/rest_api/notebook.html anonymous模式不需要用户名密码即可直接访问。如图, 根据API文档我们知道,运行模式有两种,同步和异步

    2024年01月17日
    浏览(35)
  • Apache ShenYu 学习笔记一

    这是一个异步的,高性能的,跨语言的,响应式的 API 网关。 官网文档:https://shenyu.apache.org/zh/docs/index 仓库地址:https://github.com/apache/shenyu 本次体验基本参照官方快速开始文档步骤 开发工具:IDEA JDK:1.8 IDEA打开上一步下载好的项目 找到 shenyu-admin 子项目,运行 ShenyuAdminBoo

    2024年02月01日
    浏览(59)
  • 深入探索Apache ZooKeeper:关键技术学习与实践指南

    Apache ZooKeeper,作为一款广受认可的分布式协调服务,为大型分布式系统提供了强大的数据一致性、服务注册与发现、分布式锁、配置管理等基础服务。本文将深入剖析ZooKeeper的技术内核,梳理其关键学习点,并结合实践场景给出学习与应用建议,帮助读者全方位掌握这一重要

    2024年04月28日
    浏览(40)
  • tomcat与Apache---一起学习吧之服务器

    Apache和Tomcat都是Web服务器,但它们有一些重要的区别。 Apache服务器是普通服务器,本身只支持HTML即普通网页。不过可以通过插件支持PHP,还可以与Tomcat连通(单向Apache连接Tomcat,就是说通过Apache可以访问Tomcat资源。反之不然)。 Tomcat是Java开发的一个符合JavaEE的Servlet规范的

    2024年01月25日
    浏览(37)
  • Azure - 机器学习:使用 Apache Spark 进行交互式数据整理

    关注TechLead,分享AI全维度知识。作者拥有10+年互联网服务架构、AI产品研发经验、团队管理经验,同济本复旦硕,复旦机器人智能实验室成员,阿里云认证的资深架构师,项目管理专业人士,上亿营收AI产品研发负责人。 数据整理已经成为机器学习项目中最重要的步骤之一。

    2024年02月08日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包