Java HTTPClient用法详解(附带实例)
Java 9 开始引入了一个处理 HTTP 请求的 HTTP Client API,该 API 支持同步和异步,在 Java 11 中已经进入正式可用状态,开发人员可以在 java.net 包中找到这个 API。
有人说,HttpClient 不就是一个浏览器嘛!可能不少人对 HttpClient 会产生这种误解,他们的观点是,既然 HttpClient 是一个 HTTP 客户端编程工具,那它就相当于一个浏览器,无非是不能把 HTML 渲染出页面而已。
其实,HttpClient 不是浏览器,它是一个 HTTP 通信库、一个工具包,因此它只提供一个通用浏览器应用程序所期望的功能子集。
HttpClient 与浏览器最根本的区别是,HttpClient 中没有用户界面,而浏览器需要一个渲染引擎来显示页面,并解释用户输入。HttpClient 只能以编程的方式通过其 API 用于传输和接收 HTTP 消息,它对内容也是完全不可知的。
HTTPClient API 的主要类及接口如下:
- HttpClient 类:HTTPClient API 的核心对象,用于发送请求和接收响应。Java 为创建该类提供了 HttpClient.Builder 接口。
- HttpRequest 类:代表请求对象。Java 为了创建该类提供了 HttpRequest.Builder 接口。
- HttpResponse 类:代表响应对象。
- WebSocket 接口:代表Web应用之间的Socket连接对象。
HTTPClient API 具有如下特性:
- 对大多数场景提供简单易用的阻塞模型;
- 通过异步机制支持事件通知,完整支持 HTTP 协议的特性;
- 易于建立 WebSocket 握手;
- 支持 HTTP/2,包括协议升级和服务器端推送;
- 支持 HTTPS/TLS;
- 和现有的其他实现类库相比,性能相当或有所提升,内存占用少。
Java HTTPClient发送同步GET请求
使用 HTTPClient 发送请求的步骤如下:- 创建 HttpClient 对象;
- 创建 HttpRequest 对象,如果有参数,使用 BodyPublishers 类设置请求参数;
- 调用 send() 或者 sendAsync() 方法发送请求,sendAsync() 方法用于发送异步请求。
接下来,通过案例来演示如何发送 GET 请求。
import java.io.IOException; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; public class Demo { public static void main(String[] args) throws IOException, InterruptedException { // 创建HttpClient对象 HttpClient httpClient = HttpClient.newBuilder().build(); // 创建HttpRequest对象 HttpRequest request = HttpRequest.newBuilder() // 设置请求的URL地址和参数 .uri(URI.create("http://118.190.158.17:10520/student/findAllStudent?page=1&limit=10")) // 设置请求方式为GET请求 .GET().build(); // 将服务器响应转换成字符串 HttpResponse.BodyHandler<String> bh = HttpResponse.BodyHandlers.ofString(); // 发送请求,获取服务器响应 HttpResponse<String> response = httpClient.send(request, bh); System.out.println("响应的状态码:" + response.statusCode()); System.out.println("响应头:" + response.headers()); System.out.println("响应体:" + response.body()); } }程序的运行结果如下:
响应的状态码:200
响应头:java.net.http.HttpHeaders@c84bfd11 { {content-type=[application/json], date = [Wed,
19 May 2021 02:19:48 GMT], transfer-encoding=[chunked]} }
响应体:{"code":0,"msg":null,"count":1,"data":[{"id":11,"name":"陈建","age":37,"phone":
"18538062907","school":"C语言中文网","createTime":"2021-05-18 09:58:37"}]}
Java HTTPClient发送带请求体的请求
上面的程序演示了如何发送 GET 请求,此外 HTTPClient 还可以发送 POST、DELETE 等方式的请求。接下来,通过案例来演示如何发送带请求体参数的 POST 请求。
import java.io.IOException; import java.net.CookieHandler; import java.net.CookieManager; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.time.Duration; public class Demo { public static void main(String[] args) throws IOException, InterruptedException { // 创建HttpClient对象 HttpClient httpClient = HttpClient.newBuilder().build(); // 创建HttpRequest对象 HttpRequest request = HttpRequest.newBuilder() // 设置请求的URL地址和参数 .uri(URI.create("http://118.190.158.17:10520/student/findAllStudent")) // 设置已提交表单的方式编码请求体 .headers("Content-Type", "application/x-www-form-urlencoded") // 设置请求方式为POST请求,并设置请求参数 .POST(HttpRequest.BodyPublishers.ofString("page=1&limit=10")).build(); // 将服务器响应转换成字符串 HttpResponse.BodyHandler<String> bh = HttpResponse.BodyHandlers.ofString(); // 发送请求,获取服务器响应 HttpResponse<String> response = httpClient.send(request, bh); System.out.println("响应的状态码:" + response.statusCode()); System.out.println("响应头:" + response.headers()); System.out.println("响应体:" + response.body()); System.out.println("程序运行结束"); } }程序的运行结果如下:
响应的状态码:200
响应头:java.net.http.HttpHeaders@d4d4ce68 { {content-type=[application/json], date= [Wed,
19 May 2021 02:51:10 GMT], transfer-encoding=[chunked]} }
响应体:{"code":0,"msg":null,"count":2,"data":[{"id":11,"name":"陈建","age":37,"phone":
"18538062907","school":"C语言中文网","createTime":"2021-05-18 09:58:37"},{"id":16,"name":"
张三", "age":20,"phone":"123456","school":"C语言中文网","createTime":"2021-05-19
10:35:57"}]}
程序运行结束
- 第一个实例的请求方式是 GET 请求,请求参数存放在请求头中;
- 当前实例程序发送的是 POST 请求,请求参数存放在请求体中。
具体使用哪种请求方式,以服务器接口定义规则为准。
Java HTTPClient发送异步请求
在现实网络中,网络环境千差万别,只要发送网络请求,就会不可避免地存在网络延迟,并且服务器处理请求也需要等待时间。那么通过 send() 方法发送同步请求时,在服务器返回响应之前,该方法会一直处于阻塞状态,效率比较低。为了提升程序效率,可以使用 sendAsync() 方法发送异步请求。异步请求不存在阻塞,会返回一个 CompletableFuture 对象,它代表一个将要完成的任务(但是具体何时完成,尚不确定),因此程序要为 CompletableFuture 设置消费监听器,当 CompletableFuture 代表的任务结束时监听器被触发执行。
接下来,通过案例来演示如何发送异步 POST 请求。
import java.io.IOException; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.util.concurrent.CompletableFuture; public class Demo { public static void main(String[] args) throws IOException, InterruptedException { // 创建HttpClient对象 HttpClient httpClient = HttpClient.newBuilder().build(); // 创建HttpRequest对象 HttpRequest request = HttpRequest.newBuilder() // 设置请求的URL地址和参数 .uri(URI.create("http://118.190.158.17:10520/student/findAllStudent")) // 设置已提交表单的方式编码请求体 .headers("Content-Type", "application/x-www-form-urlencoded") // 设置请求方式为POST请求,并设置请求参数 .POST(HttpRequest.BodyPublishers.ofString("page=1&limit=10")).build(); // 将服务器响应转换成字符串 HttpResponse.BodyHandler<String> bh = HttpResponse.BodyHandlers.ofString(); // 发送异步请求,获取服务器响应 httpClient.sendAsync(request, bh).thenApply(resp -> new Object[] {resp.statusCode(), resp.body()}) .thenAccept(rt -> { System.out.println("响应的状态码:" + rt[0]); System.out.println("响应体:" + rt[1]); }); System.out.println("程序运行结束"); // 程序休眠3秒 Thread.sleep(3000); } }程序的运行结果如下:
程序运行结束
响应的状态码:200
响应体:{"code":0,"msg":null,"count":2,"data":[{"id":11,"name":"陈建","age":37,"phone":
"18538062907","school":"C语言中文网","createTime":"2021-05-18 09:58:37"},{"id":16,"name": "
张三","age":20,"phone":"123456","school":"C语言中文网","createTime":"2021-05-19
10:35:57"}]}
- 第 2 段程序发送的是同步请求,响应未返回时程序被阻塞,所以先打印响应信息,然后打印“程序运行结束”;
- 当前程序中发送的是异步请求,响应未返回,程序不会阻塞,继续执行并打印“程序运行结束”。
Java WebSocket接口
WebSocket 接口类似普通的 Socket,只不过它是 Web 应用之间的 Socket 连接,通常以异步方式进行通信。通过 Java 来实现 WebSocket 客户端非常简单,只需要以下两个步骤:
- 定义一个 WebSocketListener 监听器对象,根据需要重写该监听器中的指定方法;
- 使用 WebSocketBuilder 构建 WebSocket 客户端。
接下来,通过案例来演示如何构建 WebSocket 客户端。
import java.net.URI; import java.net.http.HttpClient; import java.net.http.WebSocket; import java.util.concurrent.CompletionStage; public class Demo { public static void main(String[] args) throws InterruptedException { // 定义一个WebSocketListener监听器对象,根据需要重写该监听器中的指定方法 WebSocket.Listener listener = new WebSocket.Listener() { // 服务器端打开连接时触发该方法 @Override public void onOpen(WebSocket webSocket) { System.out.println("打开连接"); webSocket.sendText("我是C语言中文网的严站长", true); webSocket.request(1); } // 接收到服务器端返回的消息时触发该方法 @Override public CompletionStage<?> onText(WebSocket webSocket, CharSequence data, boolean last) { System.out.println(data); webSocket.request(1); return null; } }; // 传入监听器作为参数,创建WebSocket客户端 HttpClient httpClient = HttpClient.newHttpClient(); // 与服务器建立异步通信 httpClient.newWebSocketBuilder() .buildAsync(URI.create("ws://127.0.0.1:10520/mySocket"), listener); Thread.sleep(5000); } }
程序中创建了一个 WebSocket 客户端。虽然有了客户端,但是还缺少服务器端。接下来,通过案例来演示如何构建 WebSocket 服务器端:
import org.springframework.stereotype.Component; import javax.websocket.*; import javax.websocket.server.ServerEndpoint; import java.io.IOException; // 注解ServerEndpoint标识该类作为WebSocket服务器端 @ServerEndpoint(value = "/mySocket") @Component public class Demo { // 注解OnOpen修饰的方法将会在客户端连接时触发 @OnOpen public void start(Session session) { System.out.println("客户端连接进来了。sessionId: " + session.getId()); } // 注解OnMessage修饰的方法将会在客户端消息到达时触发 @OnMessage public void message(Session session, String message) { System.out.println("接收到消息: " + message); RemoteEndpoint.Basic remote = session.getBasicRemote(); try { remote.sendText("收到信息,欢迎来到AAA软件学院"); } catch (IOException e) { e.printStackTrace(); } } // 注解OnClose修饰的方法将会在客户端关闭时触发 @OnClose public void end(Session session) { System.out.println("客户端关闭了。sessionId: " + session.getId()); } // 注解OnError修饰的方法将会在客户端连接出错时触发 @OnError public void error(Session session, Throwable throwable) { System.out.println("客户端出错了。sessionId: " + session.getId()); } }服务器端程序需要首先运行,然后再运行客户端程序。客户端运行结果如下:
打开连接
收到信息,欢迎来到C语言中文网
服务器端运行结果如下:
客户端连接进来了。sessionId:0
接收到消息:我是C语言中文网的严站长
客户端出错了。sessionId:0
客户端关闭了。sessionId:0