大家好,我是二哥呀!
今天来给大家推荐一款直击痛点的 HTTP 客户端框架,可以超高效率地完成和第三方接口的对接。
在介绍本篇的主角之前,我们先来了解下 Java 生态中的 HTTP 组件库,大致可以分为三类:
JDK 自带的 HttpURLConnection 标准库;
Apache HttpComponents HttpClient;
OkHttp。
使用 HttpURLConnection 发起 HTTP 请求最大的优点是不需要引入额外的依赖,但是使用起来非常繁琐,也缺乏连接池管理、域名机械控制等特性支持。
使用标准库的最大好处就是不需要引入额外的依赖,但使用起来比较繁琐,就像直接使用 JDBC 连接数据库那样,需要很多模板代码。来发起一个简单的 HTTP POST 请求吧。
public class HttpUrlConnectionDemo { public static void main(String[] args) throws IOException { String urlString = "https://httpbin.org/post"; String bodyString = "password=123"; URL url = new URL(urlString); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("POST"); conn.setDoOutput(true); OutputStream os = conn.getOutputStream(); os.write(bodyString.getBytes("utf-8")); os.flush(); os.close(); if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { InputStream is = conn.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(is)); StringBuilder sb = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { sb.append(line); } System.out.println("响应内容:" + sb.toString()); } else { System.out.println("响应码:" + conn.getResponseCode()); } } }
HttpURLConnection 发起的 HTTP 请求比较原始,基本上算是对网络传输层的一次浅层次的封装;有了 HttpURLConnection 对象后,就可以获取到输出流,然后把要发送的内容发送出去;再通过输入流读取到服务器端响应的内容;最后打印。
不过 HttpURLConnection 不支持 HTTP/2.0,为了解决这个问题,Java 9 的时候官方的标准库增加了一个更高级别的 HttpClient,再发起 POST 请求就显得高大上多了,不仅支持异步,还支持顺滑的链式调用。
public class HttpClientDemo { public static void main(String[] args) throws URISyntaxException { HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .uri(new URI("https://postman-echo.com/post")) .headers("Content-Type", "text/plain;charset=UTF-8") .POST(HttpRequest.BodyPublishers.ofString("二哥牛逼")) .build(); client.sendAsync(request, HttpResponse.BodyHandlers.ofString()) .thenApply(HttpResponse::body) .thenAccept(System.out::println) .join(); } }
Apache HttpComponents HttpClient 支持的特性也非常丰富:
基于标准、纯净的Java语言,实现了HTTP1.0和HTTP1.1;
以可扩展的面向对象的结构实现了HTTP全部的方法;
支持加密的HTTPS协议(HTTP通过SSL协议);
Request的输出流可以避免流中内容体直接从socket缓冲到服务器;
Response的输入流可以有效的从socket服务器直接读取相应内容。
public class HttpComponentsDemo { public static void main(String[] args) throws IOException, IOException, ParseException { try (CloseableHttpClient httpclient = HttpClients.createDefault()) { HttpPost httpPost = new HttpPost("http://httpbin.org/post"); List<NameValuePair> nvps = new ArrayList<>(); nvps.add(new BasicNameValuePair("name", "二哥")); httpPost.setEntity(new UrlEncodedFormEntity(nvps, Charset.forName("UTF-8"))); try (CloseableHttpResponse response2 = httpclient.execute(httpPost)) { System.out.println(response2.getCode() + " " + EntityUtils.toString(response2.getEntity())); } } } }
OkHttp 是一个执行效率比较高的 HTTP 客户端:
支持 HTTP/2.0,当多个请求对应同一个 Host 地址时,可共用同一个 Socket;
连接池可减少请求延迟;
支持 GZIP 压缩,减少网络传输的数据大小;
支持 Response 数据缓存,避免重复网络请求;
public class OkHttpPostDemo { public static final MediaType JSON = MediaType.get("application/json; charset=utf-8"); OkHttpClient client = new OkHttpClient(); String post(String url, String json) throws IOException { RequestBody body = RequestBody.create(json, JSON); Request request = new Request.Builder() .url(url) .post(body) .build(); try (Response response = client.newCall(request).execute()) { return response.body().string(); } } public static void main(String[] args) throws IOException { OkHttpPostDemo example = new OkHttpPostDemo(); String json = "{'name':'二哥'}"; String response = example.post("https://httpbin.org/post", json); System.out.println(response); } }
那今天介绍的这款轻量级的 HTTP 客户端框架 Forest,正是基于 Httpclient和OkHttp 的,屏蔽了不同细节的 HTTP 组件库所带来的所有差异。
Forest 的字面意思是森林的意思,更内涵点的话,可以拆成For和Rest两个单词,也就是“为了Rest”(Rest为一种基于HTTP的架构风格)。 而合起来就是森林,森林由很多树木花草组成(可以理解为各种不同的服务),它们表面上看独立,实则在地下根茎交错纵横、相互连接依存,这样看就有点现代分布式服务化的味道了。 最后,这两个单词反过来读就像是Resultful。
项目地址:
https://gitee.com/dromara/forest
虽然 star 数还不是很多,但 star 趋势图正在趋于爬坡阶段,大家可以拿来作为一个练手项目,我觉得还是不错的选择。
Forest 本身是处理前端过程的框架,是对后端 HTTP API 框架的进一步封装。