Apache HttpClient 与 JDK 11+ HttpClient 完全无关,需通过 import 区分;Apache 版本发 POST 表单须手动设 Content-Type;JDK 版本不支持 HTTP/1.0 且默认无连接池;OkHttp 轻量但异常易被拦截器掩盖。

HttpClient 是 Apache 提供的底层 HTTP 客户端,不是 Java 标准库自带的
Java 11+ 虽然引入了 java.net.http.HttpClient,但很多人说的 “HttpClient” 实际指 org.apache.http.client.HttpClient(即 Apache HttpClient 4.x)。两者完全无关,包名、API 设计、生命周期管理都不同,混用会导致编译失败或运行时 NoClassDefFoundError。
常见误判场景:
- 看到项目里有
HttpClient client = HttpClients.createDefault(),就以为是 JDK 自带 —— 其实是 Apache 的 - Maven 依赖写成
org.apache.httpcomponents:httpclient却期望它支持HttpRequest.newBuilder()—— 这是 JDK 11+ 的 API
确认方式:看 import 语句。Apache 版本 import 以 org.apache.http 开头;JDK 原生版 import 是 java.net.http。
Apache HttpClient 4.x 发送 POST 表单必须显式设置 Content-Type
用 UrlEncodedFormEntity 构建表单参数时,HttpClient 不会自动加 Content-Type: application/x-www-form-urlencoded,漏掉会导致服务端收不到参数(尤其 Spring Boot 接口返回 400 或空 body)。
立即学习“Java免费学习笔记(深入)”;
正确写法要点:
- 创建
UrlEncodedFormEntity后,手动调用entity.setContentType("application/x-www-form-urlencoded; charset=UTF-8") - 或改用
UnmodifiableList.of(new BasicNameValuePair("k", "v"))+new UrlEncodedFormEntity(...),再 set 到HttpPost上 - 避免直接传字符串 body 并手动 setHeader,那样容易编码错乱
HttpPost post = new HttpPost("https://api.example.com/login");
List params = Arrays.asList(
new BasicNameValuePair("username", "admin"),
new BasicNameValuePair("password", "123")
);
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, StandardCharsets.UTF_8);
entity.setContentType("application/x-www-form-urlencoded; charset=UTF-8"); // 必须加
post.setEntity(entity);
JDK 11+ HttpClient 默认不支持 HTTP/1.0,且连接不复用
java.net.http.HttpClient 默认只协商 HTTP/1.1 或 HTTP/2,遇到只支持 HTTP/1.0 的老旧服务(如某些嵌入式设备接口),会直接抛 java.net.http.HttpTimeoutException 或连接重置。
采用HttpClient向服务器端action请求数据,当然调用服务器端方法获取数据并不止这一种。WebService也可以为我们提供所需数据,那么什么是webService呢?,它是一种基于SAOP协议的远程调用标准,通过webservice可以将不同操作系统平台,不同语言,不同技术整合到一起。 实现Android与服务器端数据交互,我们在PC机器java客户端中,需要一些库,比如XFire,Axis2,CXF等等来支持访问WebService,但是这些库并不适合我们资源有限的android手机客户端,
另外,它的默认实例(HttpClient.newBuilder().build())不开启连接池,每个请求新建 TCP 连接,高并发下性能明显差于 Apache HttpClient 的 PoolingHttpClientConnectionManager。
优化建议:
- 对接老系统时,改用
HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_0).build() - 生产环境务必复用客户端实例,并配置连接超时:
HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(5)).build() - 如需连接池、重试、响应缓存等能力,Apache HttpClient 或 OkHttp 仍是更稳妥的选择
OkHttp 比 Apache HttpClient 更轻量,但拦截器链容易掩盖真实异常
OkHttp 的 OkHttpClient 初始化成本低、API 简洁,Call.execute() 同步调用不易阻塞线程,适合 Android 和微服务间调用。但它把网络层、重定向、Gzip 解压、Cookie 管理全封装进 Interceptor 链,出问题时堆栈里看不到原始 socket 异常。
排查典型问题的方法:
- 启用日志拦截器前,先关掉所有自定义
Interceptor,确认基础请求是否通 - 捕获
IOException时,检查e.getCause()—— 真实错误(如 DNS 失败、SSLHandshakeException)常藏在 cause 里 - 使用
Response.peekBody(Long.MAX_VALUE)查看原始响应体,避免因response.body().string()被消费两次导致空内容
多数场景下,OkHttp 是比 Apache HttpClient 更现代的选择,但别把它当黑盒——尤其在线上查超时或 502 错误时,得一层层拆开拦截器看。









