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

news2024/11/27 12:35:22

4.5日学习打卡

目录:

  • 4.5日学习打卡
  • Apache Commons HttpClient
    • 简介
  • Apache HttpClient 5
    • 简介
    • 依赖
    • HttpClient 5 GET 请求
    • HttpClient 5 Fluent GET
    • HttpClient5 GET 请求参数
    • HttpClient 5 POST 请求
    • HttpClient 5 Fluent POST
    • HttpClient5 POST JSON 参数
    • HttpClient 5 设置超时
    • HttpClient 5 异步请求
    • HttpClient 5 获取 Cookie
    • HttpClient 5 读取文件内容请求
    • HttpClient 5 表单登录
    • HttpClient 5 Basic Authorization
    • HttpClient 5 Digest Authorization
    • HttpClient 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"
}

如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1582201.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一秒解决安装node-sass报错或下载慢的终极方法

1.安装node-sass-install yarn add node-sass-install 2.设置sass镜像地址 windows: 在项目内添加一个 .npmrc 文件,内容如下&#xff1a; sass_binary_sitehttps://npm.taobao.org/mirrors/node-sass/ phantomjs_cdnurlhttps://npm.taobao.org/mirrors/phantomjs/ electr…

基于Django(python+sql)的校园二手交易系统设计与实现(完整程序+开题报告+论文)

随着互联网的迅猛发展&#xff0c;校园内的二手交易市场也逐渐呈现出蓬勃的发展态势。学生们在校园生活中会产生大量的闲置物品&#xff0c;而其他学生也有可能需要这些物品。本论文研究了校园二手交易系统的需求分析、系统实现和测试三个部分&#xff0c;旨在提高校园二手交易…

第35篇:分频器<二>

Q&#xff1a;介绍完D触发器分频器概念原理之后&#xff0c;本期我们设计实现四分频D触发器分频器。 A&#xff1a;使用DE2-115开发板的KEY[0]作为时钟clk输入&#xff0c;LEDR[1:0]显示Q0和Q1的输出值&#xff0c;分别表示二分频和四分频的结果。 2个D触发器级联实现4分频的V…

Matlab进阶绘图第50期—气泡堆叠蝴蝶图

气泡堆叠蝴蝶图是堆叠蝴蝶图与气泡图的组合—在堆叠蝴蝶图每根柱子上方添加大小不同的气泡&#xff0c;用于表示另外一个数据变量&#xff08;如每根柱子各组分的平均值&#xff09;的大小。 本文利用自己制作的BarBubble工具&#xff0c;进行气泡堆叠蝴蝶图的绘制&#xff0c…

假期别闲着:REST API实战演练之创建Rest API

1、创建实体类&#xff0c;模拟实体对象 创建一个类&#xff0c;模拟数据数据库来存储数据&#xff0c;这个类就叫Person。 其代码如下&#xff1a; package com.restful;public class Person {private String name;private String about;private int birthYear;public Perso…

C++(六个默认成员函数)

目录 六个默认成员函数构造函数析构函数拷贝构造函数 总结 六个默认成员函数 默认成员函数的概念&#xff1a;如果用户不显式写&#xff0c;编译器会自动生成的函数&#xff0c;就是默认成员函数 构造函数 构造函数是六个默认成员函数之一&#xff0c;构造函数的功能类似于init…

血常规、尿检等指标就能识别卵巢癌!中山大学刘继红团队牵头,四大医学院联合构建 AI 融合模型

根据国家卫生健康委员会发布的《卵巢癌诊疗指南&#xff08;2022 版&#xff09;》&#xff0c;我国卵巢癌年发病率居女性生殖系统肿瘤第 3 位&#xff0c;仅次于子宫颈癌和子宫体恶性肿瘤&#xff0c;病死率位于女性生殖道恶性肿瘤之首&#xff0c;其 5 年生存率与诊断时的病程…

VM-UNet: Vision Mamba UNet for Medical Image Segmentation

VM-UNet: Vision Mamba UNet for Medical Image Segmentation VM-UNet&#xff1a;基于视觉Mamba UNet架构的医学图像分割 论文链接&#xff1a;http://arxiv.org/abs/2402.02491 代码链接&#xff1a;https://github.com/JCruan519/VM-UNet 1、摘要 文中利用状态空间模型SS…

Vue2 —— 学习(四)

一、收集表单数据 &#xff08;一&#xff09;介绍 前面其实已经 学过了 v-model 双向绑定事件&#xff0c;能获取到表单中的内容到 vm 实例对象中 但是前面只是收集文本框&#xff0c;下面学习一下 各种类型表单数据收集 &#xff08;单/多 选&#xff0c;下拉框&#xff0…

Java - 赋值运算符

在这个实战中&#xff0c;我们将学习赋值运算符的使用方法。首先&#xff0c;我们将介绍简单赋值运算符的基本概念和语法格式。然后&#xff0c;我们将通过案例演示来加深对赋值运算符的理解。接下来&#xff0c;我们将对比Java和Python这两种不同的编程语言&#xff0c;探讨它…

linux进阶篇:文件查找的利器——grep命令+管道操作详解

Linux文件查找的利器——grep命令管道操作详解 1 grep简介 grep (global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具&#xff0c;它能使用正则表达式搜索文本&#xff0c;并把匹配的行打印出来。 Uni…

4.2.4 理解路由器数据包过程

1、实验目的 通过本实验可以掌握&#xff1a; 了解IP路由原理了解数据包封装和解封装的概念了解路由器路由和交换过程 2、实验拓扑 观察路由器路由数据包过程的实验拓扑如图4-3所示&#xff0c;设备接口地址信息如表4-2所示。 图4-3 观察路由器路由数据包过程的实验拓扑 本…

常见深度学习之十二大激活函数【函数定义、性质、数学公式、代码实现】

目录 前言 1、激活函数的定义与作用 2、激活函数的性质 二、常见的激活函数 2.1 Sigmoid函数&#xff1a; 1. 作用 2. 优点 3. 缺点 4. 数学公式 5.Sigmoid函数实现及可视化图像 2.2 Tanh函数 1. 函数定义 2.优点 3.缺点 4.Tanh函数实现及可视化图像 2.3ReLU 函数 &#xff1a;…

盘点那些好用的FIORI App(六)-导出金税批量开票文件

着全电发票政策的推行&#xff0c;越来越多的企业由原来的纸质专票以及电子票转向了全电发票&#xff0c;全电发票与原来票的区别在于&#xff0c;企业不再需要金税盘&#xff0c;可以直接登录电子开票平台&#xff0c;开具电子发票。税务平台提供了一个可以批量上传发票进行开…

SpringBoot学习笔记三-原理分析

SpringBoot学习笔记三-原理分析 SpringBoot自动装配1.1 案例1.2 通过注解方式管理Bean1.3 小结1.4 Enable注解1.5 Import注解1.5.1 ImportSelector实现类1.5.2 导入ImportBeanDefinitionRegistrar 1.5 EnableAutoConfiguration1.6 案例 SpringBoot自动装配 当再pom.xml中导入对…

数据结构|排序总结(1)|直接插入排序

排序分类 插入排序&#xff1a;直接插入排序&#xff0c;希尔排序 选择排序&#xff1a;选择排序&#xff0c;堆排序 交换排序&#xff1a;冒泡排序&#xff0c;快速排序 归并排序 插入排序 直接插入排序 相当于摸牌&#xff0c;例如我们现在手上有{2&#xff0c;4&#xff0…

无法解析符号 ‘mybatis‘(类似这种报错)

问题&#xff1a;无法解析符号 mybatis&#xff08;类似这种报错&#xff09; 解决&#xff1a;

安科瑞用户侧35kV用户变电站系统结构【110kV/66kV/35kV】

35kV综自系统项目怎么做&#xff1f;客户群体是什么&#xff1f;能带来多大的业绩&#xff1f; 1&#xff09;主要客户群体是设计院&#xff08;电力设计院、行业设计院&#xff09;、甲方、总包。 2&#xff09;综自系统本身的体量和业绩&#xff1a; a.大约35kV&#xff08…

螺旋矩阵.

0螺旋矩阵 - 蓝桥云课 (lanqiao.cn) 题目描述 对于一个n行m列的表格&#xff0c;我们可以使用螺旋的方式给表格依次填上正整数&#xff0c;我们称填好的表格为一个螺旋矩阵。 例如&#xff0c;一个4行5列的螺旋矩阵如下&#xff1a; 1 2 3 4 5 14 15 16 17 6 13 20 19 18 7 12 …

微服务(狂神)

什么是微服务&#xff1a; 微服务方案&#xff1a; 1. SpringCloud NetFlix 2. Dubbo 3. SpringCloud Alibaba 解决了什么问题&#xff1a; 1. 服务过多&#xff0c;客户端怎么访问 2. 服务过多&#xff0c;服务间怎么传值 3. 服务过多&#xff0c;如何治理 4. 服务过多…