HttpClient 简介 HttpClient 是Apache Jakarta Common 下的子项目,用来提供高效的、最新的、功能丰富的支持HTTP协议的客户端编程工具包,并且它支持HTTP协议最新版本。我们可以使用HttpClient发送各种HTP方法。
主要特性 支持HTTP和HTTPS :实现HTTP1.0/1.1,并支持加密的HTTPS协议(SSL)。认证方案 :支持多种认证方式(如Basic, Digest, NTLM)及自定义插件认证。连接管理 :支持多线程应用,最大连接数设置和过期连接自动关闭。自动处理Cookies :自动管理Set-Cookie头并支持自定义Cookie策略。流优化和持久连接 :优化请求/响应流,支持HTTP的持久连接(Keep-Alive)。简单使用 HttpGet请求响应的一般步骤: 创建HttpClient
对象,可以使用 HttpClients.createDefault();
创建Http请求对象:
如果是无参数的GET请求,则直接使用构造方法 HttpGet(String url)
创建 HttpGet
对象即可。 如果是带参数的GET请求,则可以先使用 URIBuilder(String url)
创建对象,再调用 addParameter(String param, String value)
,或 setParameter(String param, String value)
来设置请求参数,并调用 build()
方法构建一个URI 对象。只有构造方法 HttpGet(URI uri)
来构建 HttpGet 对象。 创建 HttpResponse
,调用 HttpClient
对象的 execute(HttpUriRequest request)
发送请求,该方法返回一个 HttpResponse。调用 HttpResponse 的 getAllHeaders()、getHeaders(String name)
等方法可获取服务器的响应头;调用 HttpResponse 的 getEntity()
方法可以获取 HttpEntity 对象,该对象包装了服务器的响应内容;调用 HttpResponse 的 getStatusLine().getStatusCode()
获取响应状态码。
释放连接,包括 HttpResponse、HttpClient
HttpPost请求响应的一般步骤: 创建HttpClient
对象,可以使用 HttpClients.createDefault();
创建Http请求对象:如果是无参数的POST请求,则直接通过构造方法 HttpPost(String uri)
创建 HttpPost
对象即可。 如果是带参数的POST请求,在创建出 HttpPost
对象之后,还需要构建一个 HttpEntity
对象(如 StringEntity, UrlEncodedFormEntity ……entity接口的实现类 )设置请求参数,然后调用 HttpPost.setEntity(HttpEntity entity)
将 HttpEntity
对象添加到请求中。 创建HttpResponse
,调用 HttpClient
对象的 execute(HttpUriRequest request)
发送请求,该方法返回一个 HttpResponse。调用 HttpResponse 的 getAllHeaders()、getHeaders(String name)
等方法可获取服务器的响应头;调用 HttpResponse 的 getEntity()
方法可以获取 HttpEntity 对象,该对象包装了服务器的响应内容;调用 HttpResponse 的 getStatusLine().getStatusCode()
获取响应状态码。 释放连接,包括 HttpResponse、HttpClient 使用教程 引入Maven依赖 1 2 3 4 5 6 7 8 9 10 <dependency > <groupId > org.apache.httpcomponents</groupId > <artifactId > httpasyncclient</artifactId > <version > 4.1.5</version > </dependency > <dependency > <groupId > com.fasterxml.jackson.core</groupId > <artifactId > jackson-databind</artifactId > </dependency >
Java代码示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 public class HttpClientExamples { public static void main (String[] args) throws Exception { sendGetRequestNoParams(); sendGetRequestWithParams(); sendPostRequestNoParams(); sendPostRequestWithUser(); } public static void sendGetRequestNoParams () throws Exception { try (CloseableHttpClient httpClient = HttpClients.createDefault()) { HttpGet request = new HttpGet ("http://localhost:8080/posts/1" ); HttpResponse response = httpClient.execute(request); System.out.println("GET No Params Response Status: " + response.getStatusLine().getStatusCode()); System.out.println("Response Content: " + EntityUtils.toString(response.getEntity())); } } public static void sendGetRequestWithParams () throws Exception { try (CloseableHttpClient httpClient = HttpClients.createDefault()) { URI uri = new URIBuilder ("http://localhost:8080/posts" ) .addParameter("userId" , "1" ) .build(); HttpGet request = new HttpGet (uri); HttpResponse response = httpClient.execute(request); System.out.println("GET With Params Response Status: " + response.getStatusLine().getStatusCode()); System.out.println("Response Content: " + EntityUtils.toString(response.getEntity())); } } public static void sendPostRequestNoParams () throws Exception { try (CloseableHttpClient httpClient = HttpClients.createDefault()) { HttpPost request = new HttpPost ("http://localhost:8080/posts" ); HttpResponse response = httpClient.execute(request); System.out.println("POST No Params Response Status: " + response.getStatusLine().getStatusCode()); System.out.println("Response Content: " + EntityUtils.toString(response.getEntity())); } } public static void sendPostRequestWithUser () throws Exception { try (CloseableHttpClient httpClient = HttpClients.createDefault()) { HttpPost request = new HttpPost ("http://localhost:8080/posts" ); User user = new User ("Alice" , 25 ); ObjectMapper objectMapper = new ObjectMapper (); String jsonPayload = objectMapper.writeValueAsString(user); StringEntity entity = new StringEntity (jsonPayload); entity.setContentType("application/json" ); request.setEntity(entity); HttpResponse response = httpClient.execute(request); System.out.println("POST With User Object Response Status: " + response.getStatusLine().getStatusCode()); System.out.println("Response Content: " + EntityUtils.toString(response.getEntity())); } } } @Data @AllArgsConstructor @NoArgsConstructor class User { private String name; private int age; }
RestTemplate 简介 Spring 提供了一个 RestTemplate 模板工具类,对基于 Http 的客户端进行了封装,并且实现了对象与 JSON 的序列化与反序列化,非常方便(上面的HttpClient返回的相应是 JSON 格式的)。RestTemplate 并没有限定 Http 客户端类型,而是进行了抽象,目前常用的三种都支持:
HttpClient OKHttp JDK原生的URLConnection(默认的) RestTemplate是阻塞式的,性能没有响应式式的 WebClient 优秀
具体使用 引入Maven依赖 1 2 3 4 5 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency >
创建配置类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Configuration public class RestTemplateConfig { @Bean public RestTemplate restTemplate (RestTemplateBuilder builder) { HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory (HttpClients.createDefault()); requestFactory.setConnectTimeout(5000 ); requestFactory.setReadTimeout(10000 ); return builder .requestFactory(() -> requestFactory) .build(); } }
具体使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 @Service public class RestTemplateService { @Autowired private RestTemplate restTemplate; public String getForObjectExample () { String url = "https://jsonplaceholder.typicode.com/posts/1" ; String response = restTemplate.getForObject(url, String.class); return response; } public String postForObjectExample () { String url = "https://jsonplaceholder.typicode.com/posts" ; Map<String, Object> requestBody = new HashMap <>(); requestBody.put("title" , "foo" ); requestBody.put("body" , "bar" ); requestBody.put("userId" , 1 ); String response = restTemplate.postForObject(url, requestBody, String.class); return response; } }
常用方法 方法名 请求类型 描述 getForObject
GET 获取资源并将响应直接映射为 Java 对象。 getForEntity
GET 获取资源,返回 ResponseEntity
,包含状态码、头信息和响应体。 postForObject
POST 发送请求体,并将响应映射为 Java 对象。 postForEntity
POST 发送请求体,返回 ResponseEntity
。 put
PUT 发送 PUT 请求,无返回值。 delete
DELETE 发送 DELETE 请求,无返回值。 exchange
多种 提供更灵活的方式发送请求(支持自定义 HTTP 方法、头信息等)。 execute
多种 最底层的 HTTP 操作,可完全自定义请求。
使用 exchange
发送自定义请求 如果需要添加自定义请求头或使用复杂配置,可以使用 exchange
方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 import org.springframework.http.*;import org.springframework.web.client.RestTemplate;import java.util.HashMap;import java.util.Map;public class RestTemplateCustomExample { public static void main (String[] args) { RestTemplate restTemplate = new RestTemplate (); String url = "https://jsonplaceholder.typicode.com/posts" ; HttpHeaders headers = new HttpHeaders (); headers.setContentType(MediaType.APPLICATION_JSON); Map<String, Object> requestBody = new HashMap <>(); requestBody.put("title" , "foo" ); requestBody.put("body" , "bar" ); requestBody.put("userId" , 1 ); HttpEntity<Map<String, Object>> requestEntity = new HttpEntity <>(requestBody, headers); ResponseEntity<String> responseEntity = restTemplate.exchange( url, HttpMethod.POST, requestEntity, String.class ); System.out.println("Response Status: " + responseEntity.getStatusCode()); System.out.println("Response Body: " + responseEntity.getBody()); } }
HttpClient及其连接池使用 1. 功能模块 HttpClient 接口和实现 HttpClient
:这是 Apache HttpClient 的核心接口,定义了执行 HTTP 请求的方法CloseableHttpClient
:HttpClient 的主要实现类,提供了对 HTTP 请求的同步执行,并实现了 Closeable
接口,以便在使用完毕后释放资源。请求与相应 请求类 :包括 HttpGet
、HttpPost
、HttpPut
、HttpDelete
等,分别用于不同类型的 HTTP 请求。相应类 :HttpResponse
接口用于表示 HTTP 响应,提供方法获取状态码、响应头和响应体。HttpEntity
:表示请求或响应的内容主体,可以是流、字符串、字节数组等。【具体看 entity 接口的实现类】连接管理 HttpClientConnectionManager
:接口用于管理 HTTP 连接的生命周期。PoolingHttpClientConnectionManager
:常用的实现类,支持连接池管理,允许连接复用以提高性能,可以配置最大连接数和每个路由的最大连接数。请求配置 RequestConfig
:用于配置请求参数,如连接超时、套接字超时、代理设置、重定向策略等。SocketConfig
:用于配置套接字参数,如 TCP_NODELAY 、SO_TIMEOUT 等。身份认证 CredentialsProvider
:用于提供认证信息,支持多种认证机制(Basic、Digest、NTLM、Kerberos)。AuthCache
:缓存认证信息,减少重复认证的开销。重试和重定向 HttpRequestRetryHandler
:定义重试策略,处理请求失败后的重试逻辑。RedirectStrategy
:管理请求重定向,处理 3xx 响应状态码。异步处理 HttpAsyncClient
:提供异步 HTTP 请求的支持,通过回调接口处理异步请求的结果。拦截器 HttpRequestInterceptor
和 HttpResponseInterceptor
:允许在请求发送前和响应处理前后执行自定义逻辑,提供请求和响应的拦截和修改功能。Cookie 管理 CookieStore
:用于存储和管理 HTTP Cookie。CookieSpec
:定义 Cookie 的处理规则。2. 工作原理 连接管理器
PoolingHTTPClientConnectionManager
:用于管理HTTP连接池。通过设置最大连接数和每个路由的最大连接数,确保连接的高效复用。请求配置
HttpClient 实例化
使用 HttpClients.custom()
方法创建 CloseableHttpClient
实例,并应用连接管理器和请求配置。 CloseableHttpClient
是 HttpClient
的主要实现类,支持资源管理。创建请求
创建一个 HttpGet
实例,指定请求的 URL 。在实际应用中,可以根据需要使用 HttpPost
、HttpPut
等请求类。 执行请求
使用 httpClient.execute(httpGet)
方法执行请求,并获取 CloseableHttpResponse
对象。 连接管理器负责分配和管理连接的生命周期。 处理响应
从 HttpResponse
对象中获取状态行,检查请求是否成功。 使用 EntityUtils.toString(entity)
将响应实体转换为字符串,方便读取和处理响应数据。 资源释放
使用 try-with-resources
语法,确保 CloseableHttpClient
和 CloseableHttpResponse
在使用完毕后自动关闭,释放系统资源。 为了更好地理解 Apache HttpClient 的工作原理,下面将通过一个简单的示例代码来演示其核心组件的使用和工作流程。这段代码将展示如何创建一个 HTTP 客户端,发送 GET 请求,并处理响应。
1 2 3 4 5 <dependency > <groupId > org.apache.httpcomponents</groupId > <artifactId > httpclient</artifactId > <version > 4.5.14</version > </dependency >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 public class HttpClientExample { public static void main (String[] args) { PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager (); connManager.setMaxTotal(100 ); connManager.setDefaultMaxPerRoute(20 ); RequestConfig requestConfig = RequestConfig.custom() .setSocketTimeout(5000 ) .setConnectTimeout(5000 ) .setConnectionRequestTimeout(5000 ) .build(); try (CloseableHttpClient httpClient = HttpClients.custom() .setConnectionManager(connManager) .setDefaultRequestConfig(requestConfig) .build()) { HttpGet httpGet = new HttpGet ("https://www.example.com" ); try (CloseableHttpResponse response = httpClient.execute(httpGet)) { System.out.println("Response Status: " + response.getStatusLine()); HttpEntity entity = response.getEntity(); if (entity != null ) { String responseBody = EntityUtils.toString(entity); System.out.println("Response Body: " + responseBody); } } } catch (IOException e) { e.printStackTrace(); } } }
3. 异步请求 Apache HttpClient 的异步请求功能是通过 HttpAsyncClient
实现的,它使用 Java NIO 的非阻塞 I/O 来处理 HTTP 请求。它可以在不阻塞线程的情况下发送和接收请求,满足高并发的需求。
3.1 工作原理 非阻塞 I/O Apache HttpAsyncClient 使用 Java NIO 来实现非阻塞 I/O。请求和响应的处理可以在同一线程中进行,不需要为每一个请求单独分配一个独立的线程。 事件驱动 通过事件驱动机制处理 I/O 操作的完成。请求的完成、失败或取消会触发响应的回调方法。 回调机制 使用 FutureCallback
接口处理请求的不同结果,包括成功、失败和取消。 3.2 调优配置 为了在高并发环境下实现最佳性能,配置连接管理和线程池是关键。
连接管理器 使用 PollingHttpClientConnectionManager
管理连接池,可以设置最大连接数和每个路由的最大连接数。 IO Reactor 配置 配置 IO 线程的数量,通常设置为可用处理器的数量,以充分利用多核 CPU 的性能。 线程池 自定义线程池可以通过 ExecutorService
和 ThreadFactory
来控制异步请求的执行线程数量。 连接池 PoolingHttpClientConnectionManager
管理连接池,支持连接复用和高效的多线程环境,具体见下文。
IO Reactor 配置 IO Reactor 是 Apache HttpClient 异步客户端的核心组件之一,主要用于处理网络 I/O 操作。它的主要职责包括:
事件监听 IO Reactor 监听网络事件(如连接建立、数据到达等),并触发相应的处理操作。 使用 Java NIO 的 Selector
机制来实现高效的事件驱动。 线程管理 IO Reactor 通常包含一组 IO 线程,这些线程专门用于处理网络 I/O 操作。 这些线程的数量通常设置为可用处理器的数量,以充分利用多核 CPU 的性能 自定义线程池 线程池 主要用于管理异步请求的执行线程,它负责:
任务调度 线程池负责调度和执行异步请求的任务。 当一个异步请求被提交到 HttpClient 时,线程池会选择一个线程来执行该请求。 资源管理 线程池可以限制执行请求的线程数量,防止过多的线程导致系统资源耗尽。 通过设置线程的大小,可以人为控制并发请求的数量。 示例代码 1 2 3 4 5 6 7 8 9 10 <dependency > <groupId > org.apache.httpcomponents</groupId > <artifactId > httpasyncclient</artifactId > <version > 4.1.5</version > </dependency > <dependency > <groupId > org.apache.httpcomponents</groupId > <artifactId > httpcore-nio</artifactId > <version > 4.4.15</version > </dependency >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 public class AsyncHttpClientExample { public static void main (String[] args) throws Exception { IOReactorConfig ioReactorConfig = IOReactorConfig.custom() .setIoThreadCount(Runtime.getRuntime().availableProcessors()) .build(); PoolingNHttpClientConnectionManager connectionManager = new PoolingNHttpClientConnectionManager ( new DefaultConnectingIOReactor (ioReactorConfig)); connectionManager.setMaxTotal(100 ); connectionManager.setDefaultMaxPerRoute(20 ); ThreadFactory threadFactory = Executors.defaultThreadFactory(); ExecutorService executorService = Executors.newFixedThreadPool(10 , threadFactory); try (CloseableHttpAsyncClient httpClient = HttpAsyncClients.custom() .setConnectionManager(connectionManager) .setThreadFactory(threadFactory) .setExecutorService(executorService) .build()) { httpClient.start(); CountDownLatch latch = new CountDownLatch (1 ); HttpGet request = new HttpGet ("https://www.example.com" ); httpClient.execute(request, new FutureCallback <HttpResponse>() { @Override public void completed (HttpResponse response) { System.out.println("Response: " + response.getStatusLine()); latch.countDown(); } @Override public void failed (Exception ex) { System.out.println("Request failed: " + ex.getMessage()); latch.countDown(); } @Override public void cancelled () { System.out.println("Request cancelled" ); latch.countDown(); } }); latch.await(); } catch (Exception e) { e.printStackTrace(); } } }
4. 连接池 4.1 基本概念 Apache HttpClient 的连接池通过 PoolingHttpClientConnectionManager
提供高效的连接管理功能。它允许客户端在执行 HTTP 请求时重用连接,以提高性能和资源利用率。
4.2 基本原理 连接复用 连接池通过维护一个连接集合,允许多个请求重用同一连接,避免每次请求都需要建立和关闭连接的开销。 连接分配 当一个请求需要发送是,连接池首先检查是否有空闲连接可用。如果有,则直接复用;如果没有,则根据配置创建新的连接。 连接释放 请求完成后,连接并不立即关闭,而是被释放回池中,以便后续请求使用。 连接过期和验证 为了避免使用失效的连接,连接池会在连接空闲时间过长时对其进行验证,并根据配置自动清理过期或不再有效的连接。 4.3 关键组件和配置 PoolingHttpClientConnectionManager
核心连接管理器,负责维护连接池。 提供方法设置总连接数(setMaxTotal
)和每个路由的最大连接数(setDefaultMaxPerRoute
)。 路由(Route)
由目标主机、端口和协议组成,用于识别不同的连接路径。 可以为特定路由设置不同的最大连接数。 连接保持策略(Keep-Alive Strategy)
通过 ConnectionKeepAliveStrategy
确定连接的保持时间。 可以自定义策略,以根据响应头信息动态调整连接的保持时间。 连接验证和清理
使用 IdleConnectionEvictor
定期检查和清理空闲连接,防止资源浪费。 validateAfterInactivity
设置连接空闲时间超过某个阈值后,在使用前需要进行验证。4.4 工作机制 请求到达 客户端请求到达,连接管理器检查是否有可用的空闲连接。 如果有,则复用空闲连接;否则,根据配置创建新连接。 连接使用 请求使用连接和服务器进行通信。 完成后,连接被标记为可用,并返回连接池。 连接验证 在空闲连接重新使用前,连接管理器可能会对其进行验证,以确保连接仍然有效。 连接清理 4.5 示例代码 以下是一个示例代码,展示如何配置和使用 Apache HttpClient 的连接池:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 public class HttpClientConnectionPoolExample { public static void main (String[] args) { PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager (); connectionManager.setMaxTotal(50 ); connectionManager.setDefaultMaxPerRoute(5 ); HttpHost targetHost = new HttpHost ("www.example.com" , 80 ); connectionManager.setMaxPerRoute(new HttpRoute (targetHost), 10 ); ConnectionKeepAliveStrategy keepAliveStrategy = (HttpResponse response, HttpContext context) -> { long keepAliveDuration = 5 * 1000 ; return keepAliveDuration; }; RequestConfig requestConfig = RequestConfig.custom() .setConnectTimeout(5000 ) .setSocketTimeout(5000 ) .build(); try (CloseableHttpClient httpClient = HttpClients.custom() .setConnectionManager(connectionManager) .setDefaultRequestConfig(requestConfig) .setKeepAliveStrategy(keepAliveStrategy) .build()) { HttpGet request = new HttpGet ("http://www.example.com" ); try (CloseableHttpResponse response = httpClient.execute(request)) { System.out.println("Response Status: " + response.getStatusLine()); String responseBody = EntityUtils.toString(response.getEntity()); System.out.println("Response Body: " + responseBody); } catch (IOException e) { e.printStackTrace(); } } catch (IOException e) { e.printStackTrace(); } } }
4.6 作用范围 和 OkHttp
不同,Apache HttpClient
的连接池不仅可以控制总最大连接数(setMaxTotal
),还可以控制每个路由(每个目标主机)的最大连接数(setDefaultMaxPerRoute
),甚至还可以为特定的主机或路由指定不同的最大连接数(setMaxPerRoute
)。
虽然 OkHttp
控制不了单机的最大连接数,但是有调度器 (Dispatcher
)替代,可以实现单机最大并发请求数控制。而Apache HttpClient
中则没有类似调度器 (Dispatcher
)的组件。所以二者各有互补。
5. 和 OkHttp 对比 从性能角度来看,OkHttp 和 Apache HttpClient 各有其优劣,具体取决于使用场景和配置。以下是对两者在性能方面的详细对比:
5.1. 连接管理和复用 OkHttp
连接池 :OkHttp 内置了一个高效的连接池,自动管理连接的生命周期,默认情况下支持 HTTP/2 的多路复用,能够显著减少网络延迟。
连接复用 :通过复用连接来减少连接建立的开销,尤其是在高并发场景下,表现出色。
并发性能 :得益于 HTTP/2 支持和连接池管理,OkHttp 在处理并发请求时具有较高的吞吐量和低延迟。
Apache HttpClient
连接池管理 :使用 PoolingHttpClientConnectionManager
进行连接池管理,允许更细粒度的连接配置。
连接复用 :也支持连接复用,但需要手动配置和管理连接池,使用不当可能导致性能瓶颈。
路由控制 :提供对连接路由的详细控制,适合复杂的网络拓扑,但可能增加配置复杂性。
5.2. 协议支持 5.3. 异步处理 5.4. 缓存机制 OkHttp
Apache HttpClient
缓存支持 :需要手动实现缓存机制,Apache HttpClient 不提供开箱即用的缓存支持,增加了实现复杂性。5.5. 资源消耗 5.6. 总结 OkHttp :在现代应用中,尤其是需要 HTTP/2 和 WebSocket 支持的场景下,OkHttp 在性能上表现优异。 适合需要高并发处理和低延迟的应用场景,如移动应用和微服务架构。 内置的缓存和异步支持简化了开发,减少了资源消耗。 Apache HttpClient :在需要复杂配置和扩展的场景下,Apache HttpClient 提供了灵活性,但可能在性能上稍逊。 适合在服务器端处理复杂的 HTTP 请求,尤其是需要复杂身份验证和路由控制的场景。 需要手动优化连接管理和异步处理以提升性能。 HttpClient工具类模板 HttpClientUtil 类概述 该类是一个 HTTP 请求工具类,包含了发送 GET
和 POST
请求的功能,支持普通的表单数据和 JSON 数据的发送。它使用 Apache HttpClient
来执行 HTTP 请求,并通过配置连接超时、读取超时等参数来增强请求的稳定性。
代码注释与功能说明 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 public class HttpClientUtil { static final int TIMEOUT_MSEC = 5 * 1000 ; public static String doGet (String url, Map<String, String> paramMap) { CloseableHttpClient httpClient = HttpClients.createDefault(); String result = "" ; CloseableHttpResponse response = null ; try { URIBuilder builder = new URIBuilder (url); if (paramMap != null ) { for (String key : paramMap.keySet()) { builder.addParameter(key, paramMap.get(key)); } } URI uri = builder.build(); HttpGet httpGet = new HttpGet (uri); response = httpClient.execute(httpGet); if (response.getStatusLine().getStatusCode() == 200 ) { result = EntityUtils.toString(response.getEntity(), "UTF-8" ); } } catch (Exception e) { e.printStackTrace(); } finally { try { response.close(); httpClient.close(); } catch (IOException e) { e.printStackTrace(); } } return result; } public static String doPost (String url, Map<String, String> paramMap) throws IOException { CloseableHttpClient httpClient = HttpClients.createDefault(); CloseableHttpResponse response = null ; String resultString = "" ; try { HttpPost httpPost = new HttpPost (url); if (paramMap != null ) { List<NameValuePair> paramList = new ArrayList <>(); for (Map.Entry<String, String> param : paramMap.entrySet()) { paramList.add(new BasicNameValuePair (param.getKey(), param.getValue())); } UrlEncodedFormEntity entity = new UrlEncodedFormEntity (paramList); httpPost.setEntity(entity); } httpPost.setConfig(builderRequestConfig()); response = httpClient.execute(httpPost); resultString = EntityUtils.toString(response.getEntity(), "UTF-8" ); } catch (Exception e) { throw e; } finally { try { response.close(); } catch (IOException e) { e.printStackTrace(); } } return resultString; } public static String doPost4Json (String url, Map<String, String> paramMap) throws IOException { CloseableHttpClient httpClient = HttpClients.createDefault(); CloseableHttpResponse response = null ; String resultString = "" ; try { HttpPost httpPost = new HttpPost (url); if (paramMap != null ) { JSONObject jsonObject = new JSONObject (); for (Map.Entry<String, String> param : paramMap.entrySet()) { jsonObject.put(param.getKey(), param.getValue()); } StringEntity entity = new StringEntity (jsonObject.toString(), "utf-8" ); entity.setContentEncoding("utf-8" ); entity.setContentType("application/json" ); httpPost.setEntity(entity); } httpPost.setConfig(builderRequestConfig()); response = httpClient.execute(httpPost); resultString = EntityUtils.toString(response.getEntity(), "UTF-8" ); } catch (Exception e) { throw e; } finally { try { response.close(); } catch (IOException e) { e.printStackTrace(); } } return resultString; } private static RequestConfig builderRequestConfig () { return RequestConfig.custom() .setConnectTimeout(TIMEOUT_MSEC) .setConnectionRequestTimeout(TIMEOUT_MSEC) .setSocketTimeout(TIMEOUT_MSEC) .build(); } }
使用方法 发送 GET 请求 1 2 3 4 5 6 7 8 9 String url = "https://www.example.com/api" ;Map<String, String> params = new HashMap <>(); params.put("param1" , "value1" ); params.put("param2" , "value2" ); String response = HttpClientUtil.doGet(url, params);System.out.println(response);
发送 POST 请求(表单数据) 1 2 3 4 5 6 7 8 9 String url = "https://www.example.com/api" ;Map<String, String> params = new HashMap <>(); params.put("param1" , "value1" ); params.put("param2" , "value2" ); String response = HttpClientUtil.doPost(url, params);System.out.println(response);
发送 POST 请求(JSON 数据) 1 2 3 4 5 6 7 8 9 String url = "https://www.example.com/api" ;Map<String, String> params = new HashMap <>(); params.put("param1" , "value1" ); params.put("param2" , "value2" ); String response = HttpClientUtil.doPost4Json(url, params);System.out.println(response);
总结 doGet
方法用于发送 GET 请求,支持 URL 参数传递。doPost
方法用于发送 POST 请求,支持表单数据。doPost4Json
方法用于发送 POST 请求,支持 JSON 数据格式。这些方法统一返回请求的响应内容(字符串形式)。使用时,只需要调用相应的方法并传入 URL 和参数即可。