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

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() {@Overridepublic void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {}@Overridepublic void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {}@Overridepublic 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=11getM.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对象,设置请求的URLHttpGet 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对象的URIhttpGet.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.1System.out.println(response.getCode()); // 200System.out.println(response.getReasonPhrase()); // OKHttpEntity 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对象,设置请求的URLHttpPost 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.1System.out.println(response.getCode()); // 200System.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.1System.out.println(response.getCode()); // 200System.out.println(response.getReasonPhrase()); // OKHttpEntity 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 clinethttpclient.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 clinethttpclient.start();// 根据请求响应情况进行回调操作CountDownLatch latch = new CountDownLatch(1);SimpleHttpRequest request = SimpleHttpRequests.get(url);httpclient.execute(request, new FutureCallback<SimpleHttpResponse>() {@Overridepublic void completed(SimpleHttpResponse response2) {latch.countDown();System.out.println("getAsync2:" + request.getRequestUri() + "->" + response2.getCode());}@Overridepublic void failed(Exception ex) {latch.countDown();System.out.println("getAsync2:" + request.getRequestUri() + "->" + ex);}@Overridepublic 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 clinethttpclient.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;@Overrideprotected void start(HttpResponse response, ContentType contentType) throws HttpException, IOException {System.out.println("getAsync3: 开始响应....");this.response = response;}@Overrideprotected int capacityIncrement() {return Integer.MAX_VALUE;}@Overrideprotected void data(CharBuffer data, boolean endOfStream) throws IOException {System.out.println("getAsync3: 收到数据....");// Do something useful}@Overrideprotected HttpResponse buildResult() throws IOException {System.out.println("getAsync3: 接收完毕...");return response;}@Overridepublic void releaseResources() {}};httpclient.execute(producer, consumer3, new FutureCallback<HttpResponse>() {@Overridepublic void completed(HttpResponse response) {latch.countDown();System.out.println("getAsync3: "+request.getRequestUri() + "->" + response.getCode());}@Overridepublic void failed(Exception ex) {latch.countDown();System.out.println("getAsync3: "+request.getRequestUri() + "->" + ex);}@Overridepublic 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 请求上下文 HttpClientContextfinal HttpClientContext localContext = HttpClientContext.create();// 绑定 cookieStore 到 localContextlocalContext.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);@Overridepublic 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 响应,并自定义响应的内容。@Overridepublic 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.mzph.cn/news/804626.shtml

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

相关文章

Java中利用BitMap位图实现海量级数据去重

&#x1f3f7;️个人主页&#xff1a;牵着猫散步的鼠鼠 &#x1f3f7;️系列专栏&#xff1a;Java全栈-专栏 &#x1f3f7;️个人学习笔记&#xff0c;若有缺误&#xff0c;欢迎评论区指正 目录 前言 什么是BitMap&#xff1f;有什么用&#xff1f; 基本概念 位图的优势 …

加快构建数字影像优势 成都文创产业园区持续发力

在数字化时代的浪潮下&#xff0c;成都文创产业园区以其前瞻性的视野和战略布局&#xff0c;正加快构建数字影像优势&#xff0c;成都文创产业园区持续发力&#xff0c;为城市的文化创意产业发展注入新动力。国际数字影像产业园作为其中的佼佼者&#xff0c;以其三大生态服务体…

GitHub 仓库 (repository) Watch - Star - Fork - Follow

GitHub 仓库 [repository] Watch - Star - Fork - Follow References 眼睛图标旁边写着 Watch 字样。点击这个按钮就可以 Watch 该仓库&#xff0c;今后该仓库的更新信息会显示在用户的公开活动中。Star 旁边的数字表示给这个仓库添加 Star 的人数。这个数越高&#xff0c;代表…

小白学Java成长日记特别篇

晚上好&#xff0c;各位小伙伴。今天给大家带来的是Java的输出补充篇&#xff0c;前两篇说了输出和输入的大概&#xff0c;但我没有详细讲它俩&#xff0c;因此这篇文章来详细的聊一聊它俩。那么废话不多说&#xff0c;我们赶紧进入正题。 首先讲一讲这个Java的输出吧。 输出格…

SpringBoot集成Skywalking日志收集

在实际项目中&#xff0c;为了方便线上排查问题&#xff0c;尤其是微服务之间调用链路比较复杂的系统中&#xff0c;通过可视化日志的手段仍然是最直接也很方便的排查定位问题的手段&#xff0c;比如大家熟悉的ELK就是一种比较成熟的可视化日志展现方式&#xff0c;在skywalkin…

书生·浦语大模型第二期实战营第二课笔记和基础作业

来源&#xff1a; 作业要求:Homework - Demo 文档教程:轻松玩转书生浦语大模型趣味 Demo B站教程:轻松玩转书生浦语大模型趣味 Demo 1. 笔记 2.基础作业 2.1 作业要求 2.2 算力平台 2.3 新建demo目录&#xff0c;以及新建目录下的文件&#xff0c;下载模型参数 2.4 Intern…

谷歌seo自然搜索排名怎么提升快?

要想在谷歌上排名快速上升&#xff0c;关键在于运用GPC爬虫池跟高低搭配的外链组合 首先你要做的&#xff0c;就是让谷歌的蜘蛛频繁来你的网站&#xff0c;网站需要被谷歌蜘蛛频繁抓取和索引&#xff0c;那这时候GPC爬虫池就能派上用场了&#xff0c;GPC爬虫池能够帮你大幅度提…

LangChain - Chain

文章目录 1、概览为什么我们需要链? 2、快速入门 (Get started) - Using LLMChain多个变量 使用字典输入在 LLMChain 中使用聊天模型&#xff1a; 3、异步 API4、不同的调用方法__call__调用仅返回输出键值 return_only_outputs只有一个输出键 run只有一个输入键 5、自定义cha…

蓝桥杯嵌入式(G431)备赛笔记——UART

printf的重定向 为了方便使用&#xff0c;通过keil中的Help功能的帮助&#xff0c;做一个printf的重定向 搜索fputc&#xff0c;复制这段 将复制的那段放入工程中&#xff0c;并添加串口发送的函数 关键代码 u8 rx_buff[30]; // 定义一个长度为30的接收缓冲区数组rx_buff u8…

“数字大冒险:探索二分查找的神奇之旅“

前言 作者&#xff1a;小蜗牛向前冲 专栏&#xff1a;小蜗牛算法之路 专栏介绍&#xff1a;"蜗牛之道&#xff0c;攀登大厂高峰&#xff0c;让我们携手学习算法。在这个专栏中&#xff0c;将涵盖动态规划、贪心算法、回溯等高阶技巧&#xff0c;不定期为你奉上基础数据结构…

算法:多重背包问题dp

文章目录 一、多重背包问题特点1.1、多重背包问题的特征1.2、解决多重背包问题的基本方法典型例题&#xff1a;AcWing——多重背包问题I 1.3、二进制优化1.3.1、二进制优化的思想1.3.2、多重背包问题的二进制优化 一、多重背包问题特点 多重背包问题是背包问题的又一变种&…

如何在Flutter应用中配置ipa Guard进行混淆

在移动应用开发中&#xff0c;保护应用代码安全至关重要。Flutter 提供了简单易用的混淆工具&#xff0c;帮助开发者在构建 release 版本应用时有效保护代码。本文将介绍如何在 Flutter 应用中使用混淆&#xff0c;并提供了相关的操作步骤和注意事项。 &#x1f4dd; 摘要 本…

彩虹聚合DNS管理系统源码

聚合DNS管理系统可以实现在一个网站内管理多个平台的域名解析&#xff0c;目前已支持的域名平台有&#xff1a;阿里云、腾讯云、华为云、西部数码、CloudFlare。本系统支持多用户&#xff0c;每个用户可分配不同的域名解析权限&#xff1b;支持API接口&#xff0c;支持获取域名…

LeetCode-冗余连接(并查集)

每日一题&#xff0c;今天又刷到一道使用并查集来解决的问题&#xff0c;再次加深了一遍自己对并查集的印象和使用。 题目要求 树可以看成是一个连通且 无环 的 无向 图。 给定往一棵 n 个节点 (节点值 1&#xff5e;n) 的树中添加一条边后的图。添加的边的两个顶点包含在 1…

对象参数验证工具, 解决非controller层数据校验问题, @Validated、@Valid

工具类 package com.common;import com.common.SysException;import javax.validation.ConstraintViolation; import javax.validation.Validation; import javax.validation.Validator; import java.util.Set; import java.util.stream.Collectors;/**1. author: 0i773. Desc…

【计算机毕业设计】超市进销存管理系统——后附源码

&#x1f389;**欢迎来到我的技术世界&#xff01;**&#x1f389; &#x1f4d8; 博主小档案&#xff1a; 一名来自世界500强的资深程序媛&#xff0c;毕业于国内知名985高校。 &#x1f527; 技术专长&#xff1a; 在深度学习任务中展现出卓越的能力&#xff0c;包括但不限于…

PostgreSQL入门到实战-第八弹

PostgreSQL入门到实战 PostgreSQL数据过滤(一)官网地址PostgreSQL概述PostgreSQL的where子命令介绍PostgreSQL的where子命令实操更新计划 PostgreSQL数据过滤(一) 官网地址 声明: 由于操作系统, 版本更新等原因, 文章所列内容不一定100%复现, 还要以官方信息为准 https://ww…

数据结构---顺序表实现

目录 1.顺序表 2.动态顺序表的实现 &#xff08;4&#xff09;顺序表初始化 &#xff08;5&#xff09;顺序表销毁 &#xff08;6&#xff09;顺序表的插入 a.尾插 b.头插 &#xff08;7&#xff09;顺序表的删除 a.尾删 b.头删 &#xff08;8&#xff09;指定位置之…

大话设计模式之桥接模式

桥接模式是一种结构型设计模式&#xff0c;它将抽象部分与它的实现部分分离&#xff0c;使它们可以独立地变化。这种模式通过提供一个桥接接口来实现这种分离&#xff0c;使得抽象部分和实现部分可以在运行时独立地进行修改。 桥接模式主要由两个部分组成&#xff1a;抽象部分…

Chat Ollama docker部署及运行 本地大语言模型+本地知识库搭建 强烈推荐

背景介绍 Ollama 是目前最流行的大模型本地化工具之一。 Ollama 支持一系列开源大模型&#xff0c;包括主流的聊天模型和文本嵌入模型&#xff08;Embedding Models&#xff09;等。 ChatOllama 是基于 Ollama 的 Web 应用&#xff0c;它可以让用户直接在浏览器中使用 Ollama。…