HttpUtils工具类(二)Apache HttpClient 5 使用详细教程

响叮当! 2024-10-05 12:37:02 阅读 52

        

目录

一、Apache HttpClient 5介绍

(1)核心特性

(2)Apache HttpClient 5 的新特性

(3)在 Java 项目的主要使用场景及缺点

使用场景:

缺点:

二、在实际项目中的应用

(1)引入maven配置

(2)自定义HttpUtils工具类---实现连接管理、重试策略等

功能概述

(3)代码中的具体实现

1、Get请求

2、POST请求-常规

3、POST请求-上传文件

(4)高级用法

1、处理重定向

2、SSL/TLS 支持

3、处理异步请求

4、处理 Cookie

5、HTTPDNS支持


一、Apache HttpClient 5介绍

Apache HttpClient 5 是一个功能齐全且高度可定制的 HTTP 客户端库, 其专门用于发送 HTTP 请求、处理 HTTP 响应并支持各种 HTTP 协议特性。特别适合处理复杂的 HTTP 请求需求,如多协议支持、认证、连接池、代理等。它适合中大型项目或需要高级 HTTP 特性的应用开发。

(1)核心特性

功能强大:

同步与异步支持:支持同步和异步的 HTTP 请求处理,异步请求在处理大量并发请求时能够显著提高效率。连接池管理:内置的连接池机制能提高并发处理性能,减少资源消耗。多种认证机制:支持多种认证方式,包括 Basic、Digest、NTLM、Kerberos 等,能够处理多种安全场景。支持Cookie管理:内置 Cookie 管理功能,能够自动处理服务端返回的 Cookie 并在后续请求中使用,模拟浏览器行为。

协议支持广泛:

HTTP/1.1 和 HTTP/2 支持:支持现代 HTTP 协议,包括 HTTP/2 的多路复用和流优先级等特性,提升了网络请求效率;特别是 HTTP/2 多路复用的优势。SSL/TLS 支持:支持 HTTPS,提供自定义 SSL/TLS 配置,确保通信的安全性。HttpClient 5 可以方便地处理 HTTPS 请求,支持定制化的 SSL/TLS 配置。

灵活性和可扩展性:

易于扩展和定制:允许开发者根据需要进行灵活的定制,HttpClient 5 的设计高度模块化,用户可以根据需要对连接管理、重定向策略、请求重试策略、代理设置等进行灵活定制。代理支持:可以轻松配置 HTTP 或 SOCKS 代理,用于跨网络访问和隐私保护。

健壮的错误处理机制:

自动重试和重定向处理:内置的重试机制和自动重定向处理,可以减少由于网络问题导致的失败请求。开发者可以定制是否启用自动重定向。

(2)Apache HttpClient 5 的新特性

与之前的 4.x 版本相比,HttpClient 5 进行了大量的改进和优化,特别是在性能和安全性方面:

HTTP/2 支持:提供了完整的 HTTP/2 支持,包括多路复用、流优先级等特性。更好的异步支持:在处理并发请求时,通过异步模型极大提升了响应速度和吞吐量。灵活的响应处理:通过改进的响应处理 API,可以更方便地处理大型响应体,避免内存溢出问题。

(3)在 Java 项目的主要使用场景及缺点

使用场景:

RESTful API 客户端:与第三方 API 交互,发送各种 HTTP 请求。Web 爬虫:抓取网页内容,处理重定向、Cookie 等。分布式系统通信:用于微服务间的 HTTP 通信。测试与自动化:模拟 HTTP 请求,进行集成和自动化测试。代理与网关:处理请求代理和认证机制。文件上传下载:实现大文件的传输。认证交互:处理 OAuth2、JWT 等认证协议。安全通信:处理 HTTPS 请求,确保数据安全。

缺点:

学习曲线陡峭:高级特性(如自定义连接池、SSL 配置、异步请求等)较为复杂,新手需要时间学习和掌握。体积较大:相比轻量级客户端,如 OkHttp,HttpClient 依赖库较多,可能不适合小型项目。性能消耗高:默认配置下的内存和 CPU 占用较高,需调整才能达到最佳性能。配置繁琐:高级定制(如连接管理、认证、代理)需要较多配置,增加开发复杂度。异步编程复杂:异步请求的回调、错误处理等逻辑复杂,增加代码难度。

二、在实际项目中的应用

(1)引入maven配置

首先,你需要将 HttpClient 5 的依赖加入到项目中。<code>pom.xml 文件如下:

<dependency>

<groupId>org.apache.httpcomponents.client5</groupId>

<artifactId>httpclient5</artifactId>

<version>5.1</version>

</dependency>

(2)自定义HttpUtils工具类---实现连接管理、重试策略等

import lombok.extern.slf4j.Slf4j;

import org.apache.hc.client5.http.DnsResolver;

import org.apache.hc.client5.http.classic.methods.HttpPost;

import org.apache.hc.client5.http.classic.methods.HttpUriRequestBase;

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.client5.http.impl.io.PoolingHttpClientConnectionManager;

import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;

import org.apache.hc.core5.http.HttpEntity;

import org.apache.hc.core5.http.io.SocketConfig;

import org.apache.hc.core5.http.message.BasicHeader;

import org.apache.hc.core5.util.Timeout;

import org.springframework.stereotype.Component;

import java.io.Closeable;

import java.io.IOException;

import java.net.InetAddress;

import java.net.URI;

import java.net.UnknownHostException;

import java.util.Map;

/**

* @author 响叮当

* @since 2024/8/15 14:10

**/

@Slf4j

@Component

public class ApacheHttpClientUtil {

private CloseableHttpClient httpClient;

@PostConstruct

public void init() {

SocketConfig socketConfig = SocketConfig.custom()

.setSoTimeout(Timeout.ofMilliseconds(1000))

.build();

PoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder

.create()

.setDefaultSocketConfig(socketConfig)

.setMaxConnTotal(1000)

.setMaxConnPerRoute(50)

.build();

RequestConfig requestConfig = RequestConfig.custom()

.setConnectionRequestTimeout(Timeout.ofMilliseconds(8000))

.setResponseTimeout(Timeout.ofMilliseconds(8000))

.setConnectTimeout(Timeout.ofMilliseconds(8000))

.build();

httpClient = HttpClients

.custom()

.disableContentCompression()

.setConnectionManager(connectionManager)

.setDefaultRequestConfig(requestConfig)

.build();

}

public CloseableHttpResponse getOrHead(String url, String method, Map<String, String> headers) throws IOException {

HttpUriRequestBase request = new HttpUriRequestBase(method, URI.create(url));

BasicHeader[] head = mapToHeaders(headers);

request.setHeaders(head);

return httpClient.execute(request);

}

public CloseableHttpResponse post(String url, Map<String, String> headers, HttpEntity httpEntity) throws IOException {

HttpPost request = new HttpPost(url);

BasicHeader[] head = mapToHeaders(headers);

request.setHeaders(head);

request.setEntity(httpEntity);

return httpClient.execute(request);

}

public static BasicHeader[] mapToHeaders(Map<String, String> map) {

BasicHeader[] headers = new BasicHeader[map.size()];

int i = 0;

for (Map.Entry<String, String> entry : map.entrySet()) {

headers[i++] = new BasicHeader(entry.getKey(), entry.getValue());

}

return headers;

}

public static void closeQuietly(Closeable is) {

if (is != null) {

try {

is.close();

} catch (Exception ex) {

log.error("Resources encounter an exception when closing,ex:{}", ex.getMessage());

}

}

}

}

功能概述

初始化 HTTP 客户端init() 方法初始化 CloseableHttpClient,配置连接池、请求超时和套接字超时。

连接池配置:通过 PoolingHttpClientConnectionManagerBuilder 设置最大连接数(1000)和每路由的最大连接数(50),用于高并发场景。请求配置:包括连接超时、请求超时和响应超时,确保在合理的时间内处理请求。HTTP 请求处理

GET/HEAD 请求getOrHead() 方法可发送 GET 或 HEAD 请求,并接受自定义请求头。POST 请求post() 方法可发送 POST 请求,支持自定义请求头和实体。资源管理closeQuietly() 方法用于关闭资源,避免抛出异常。

(3)代码中的具体实现

1、Get请求

@GetMapping("/get")

public void testGet() {

String url = "http://xxx.com.cn";

try {

// 1、构建入参、添加 headers

Map<String, String> headers = new HashMap<>();

// 2、发起http请求

CloseableHttpResponse httpResponse = apacheHttpClientUtil.getOrHead(url, "GET", headers);

// 3、返回结果,异常处理

if (httpResponse.getCode() == 200) {

String resStr = EntityUtils.toString(httpResponse.getEntity());

log.info("request_success, response:{}, httpResponse_Code:{}, reasonPhrase:{}", resStr, httpResponse.getCode(), httpResponse.getReasonPhrase());

} else {

log.error("request_fail, httpResponse_Code:{}, reasonPhrase:{}", httpResponse.getCode(), httpResponse.getReasonPhrase());

}

} catch (Exception e) {

log.error("request_udmp_fail, ex:{}", e);

}

}

2、POST请求-常规

@PostMapping("/post")

public void testPost(@RequestBody PostReq req) {

String url = "http://xxx.com.cn";

try {

// 1、构建入参、添加 headers

StringEntity stringEntity = new StringEntity(JSONUtil.toJsonStr(req), ContentType.APPLICATION_JSON);

Map<String, String> headers = new HashMap<>();

// 2、发起http请求

CloseableHttpResponse httpResponse = apacheHttpClientUtil.post(url, headers, stringEntity);

// 3、返回结果,异常处理

if (httpResponse.getCode() == 200) {

String resStr = EntityUtils.toString(httpResponse.getEntity());

log.info("request_success, response:{}, httpResponse_Code:{}, reasonPhrase:{}", resStr, httpResponse.getCode(), httpResponse.getReasonPhrase());

} else {

log.error("request_fail, httpResponse_Code:{}, reasonPhrase:{}", httpResponse.getCode(), httpResponse.getReasonPhrase());

}

} catch (Exception e) {

log.error("request_udmp_fail, ex:{}", e);

}

}

3、POST请求-上传文件

/**

* 上传文件

* @param multipartFile

* @param token

* @param key

* @return

*/

@PostMapping("/uploadFile")

public UploadRes testPostFile(

@RequestParam("file") MultipartFile multipartFile,

@RequestParam("token") String token,

@RequestParam("key") String key

) {

UploadRes res = null;

String url = "http://xxx.com.cn";

try {

// 1、构建File参数

File file = new File(multipartFile.getOriginalFilename());

try (FileOutputStream fos = new FileOutputStream(file)) {

fos.write(multipartFile.getBytes());

}

MultipartEntityBuilder builder = MultipartEntityBuilder.create();

builder.addBinaryBody("file", file, ContentType.MULTIPART_FORM_DATA, "ex.xlsx");

// 2、构建其他参数

builder.addTextBody("token", token, ContentType.TEXT_PLAIN);

builder.addTextBody("key", key, ContentType.TEXT_PLAIN);

HttpEntity multipartEntity = builder.build();

// 3、需要加 header,在这里加

Map<String, String> headers = new HashMap<>();

// 4、发起http请求

CloseableHttpResponse httpResponse = apacheHttpClientUtil.post(url, headers, multipartEntity);

// 5、返回结果,异常处理

if (httpResponse.getCode() == 200) {

String resStr = EntityUtils.toString(httpResponse.getEntity());

res = JSONUtil.toBean(resStr, UploadRes.class);

log.info("request_success, response:{}, httpResponse_Code:{}, reasonPhrase:{}", resStr, httpResponse.getCode(), httpResponse.getReasonPhrase());

} else {

log.error("request_fail, httpResponse_Code:{}, reasonPhrase:{}", httpResponse.getCode(), httpResponse.getReasonPhrase());

}

} catch (Exception e) {

log.error("request_udmp_fail, ex:{}", e);

}

return res;

}

(4)高级用法

1、处理重定向

HttpClient 5 默认会处理 3XX 重定向,但你也可以自定义行为。

CloseableHttpClient httpClient = HttpClients.custom()

.disableRedirectHandling() // 禁用自动重定向

.build();

2、SSL/TLS 支持

使用 HttpClient 5 可以轻松处理 HTTPS 请求,下面展示如何自定义 SSL 配置。

import org.apache.hc.core5.ssl.SSLContextBuilder;

import org.apache.hc.client5.http.impl.classic.HttpClients;

import javax.net.ssl.SSLContext;

SSLContext sslContext = SSLContextBuilder.create()

.loadTrustMaterial((chain, authType) -> true) // 信任所有证书

.build();

CloseableHttpClient httpClient = HttpClients.custom()

.setSSLContext(sslContext)

.build();

3、处理异步请求

如果你需要发送异步 HTTP 请求,可以使用 HttpAsyncClient

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.client5.http.classic.methods.HttpGet;

CloseableHttpAsyncClient asyncClient = HttpAsyncClients.createDefault();

asyncClient.start();

HttpGet request = new HttpGet("https://jsonplaceholder.typicode.com/posts/1");

asyncClient.execute(request, new FutureCallback<>() {

@Override

public void completed(CloseableHttpResponse response) {

System.out.println("Response received: " + response.getCode());

}

@Override

public void failed(Exception ex) {

System.out.println("Request failed: " + ex.getMessage());

}

@Override

public void cancelled() {

System.out.println("Request cancelled");

}

});

4、处理 Cookie

import org.apache.hc.client5.http.cookie.BasicCookieStore;

import org.apache.hc.client5.http.impl.classic.HttpClients;

import org.apache.hc.client5.http.cookie.CookieStore;

CookieStore cookieStore = new BasicCookieStore();

CloseableHttpClient httpClient = HttpClients.custom()

.setDefaultCookieStore(cookieStore)

.build();

5、HTTPDNS支持

// 当域名为www.baidu.com结尾时候,转到local的机器上

String Target_IP= "127.0.0.1";

String[] domains = new String[]{"www.baidu.com"};

DnsResolver dnsResolver = new DnsResolver() {

@Override

public InetAddress[] resolve(String host) throws UnknownHostException {

if (host.endsWith(domains[0]))) {

return new InetAddress[]{InetAddress.getByName(Target_IP)};

}

return new InetAddress[0];

}

@Override

public String resolveCanonicalHostname(String s) {

return null;

}

};

// @PostConstruct

public void init() {

SocketConfig socketConfig = SocketConfig.custom()

.setSoTimeout(Timeout.ofMilliseconds(1000))

.build();

PoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder

.create()

.setDnsResolver(dnsResolver) // 这里是HttpDns配置

.setDefaultSocketConfig(socketConfig)

.setMaxConnTotal(1000)

.setMaxConnPerRoute(50)

.build();



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。