从 Java 1.1 开始,JDK 提供的核心库中就有一个 HTTP 客户端。Java 11 添加了一个新的客户端。如果您对向项目中添加额外的依赖项敏感,其中之一可能是一个不错的选择。
Java 1.1 HttpURL连接
以下是您将如何使用它来发出GET请求以获取 APOD 数据:
// Create a neat value object to hold the URL
URL url = new URL("https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY");
// Open a connection(?) on the URL(??) and cast the response(???)
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// Now it's "open", we can set the request method, headers etc.
connection.setRequestProperty("accept", "application/json");
// This line makes the request
InputStream responseStream = connection.getInputStream();
// Manually converting the response body InputStream to APOD using Jackson
ObjectMapper mapper = new ObjectMapper();
APOD apod = mapper.readValue(responseStream, APOD.class);
// Finally we have the response
System.out.println(apod.title);
Java 11 HttpClient
HttpClient 接受BodyHandler可以将 HTTP 响应转换为您选择的类。有一些内置的处理程序:String,byte[]用于二进制数据,Stream按行分割,还有一些其他的。BodyHandler您也可以定义自己的,这可能会有所帮助,因为没有用于解析 JSON的内置函数。我已经按照 Java Docs 中的示例基于 Jackson 编写了一个(此处)。它为APOD 类返回一个,因此我们在需要结果时调用。Supplier.get()
这是一个同步请求:
// create a client
var client = HttpClient.newHttpClient();
// create a request
var request = HttpRequest.newBuilder(
URI.create("https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY"))
.header("accept", "application/json")
.build();
// use the client to send the request
var response = client.send(request, new JsonBodyHandler<>(APOD.class));
// the response:
System.out.println(response.body().get().title);
对于异步请求,clientandrequest以相同的方式进行,然后调用.sendAsync而不是.send:
// use the client to send the request
var responseFuture = client.sendAsync(request, new JsonBodyHandler<>(APOD.class));
// We can do other things here while the request is in-flight
// This blocks until the request is complete
var response = responseFuture.get();
// the response:
System.out.println(response.body().get().title);
如果内置客户端不适合您,请不要担心!您可以将许多库引入您的项目中,它们可以完成这项工作。
Apache HttpClient
Apache Software Foundation 的 HTTP客户端已经存在了很长时间。它们被广泛使用,并且是许多高级库的基础。历史有点混乱。旧的Commons HttpClient不再开发,新版本(也称为 HttpClient)在HttpComponents项目下。5.0 版于 2020 年初发布,增加了 HTTP/2 支持。该库还支持同步和异步请求。
总体而言,API 相当低级 - 您需要自己实现很多。以下代码调用 NASA API。
ObjectMapper mapper = new ObjectMapper();
try (CloseableHttpClient client = HttpClients.createDefault()) {
HttpGet request = new HttpGet("https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY");
APOD response = client.execute(request, httpResponse ->
mapper.readValue(httpResponse.getEntity().getContent(), APOD.class));
System.out.println(response.title);
}
OkHttp
OkHttp是Square的 HTTP 客户端,具有许多有用的内置功能,例如自动处理 GZIP、响应缓存和重试或在网络错误的情况下回退到其他主机以及 HTTP/2 和 WebSocket 支持。尽管没有内置的 JSON 响应解析,但 API 是干净的,所以我再次添加了代码来解析 JSON 与 Jackson:
ObjectMapper mapper = new ObjectMapper();
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY")
.build(); // defaults to GET
Response response = client.newCall(request).execute();
APOD apod = mapper.readValue(response.body().byteStream(), APOD.class);
System.out.println(apod.title);
这很好,但是当您在顶部添加 Retrofit 时,OkHttp 的真正威力就很明显了。
Retrofit
Retrofit是 Square 的另一个库,建立在 OkHttp 之上。除了 OkHttp 的所有低级特性外,它还添加了一种构建 Java 类的方法,这些类抽象了 HTTP 细节并提供了一个很好的 Java 友好 API。
首先,我们需要创建一个接口来声明我们想要针对 APOD API 调用的方法,并使用注释定义这些方法如何对应于 HTTP 请求:
public interface APODClient {
@GET("/planetary/apod")
@Headers("accept: application/json")
CompletableFuture<APOD> getApod(@Query("api_key") String apiKey);
}
返回类型CompletableFuture<APOD>使其成为异步客户端。Square 提供其他适配器,或者您可以编写自己的适配器。
在声明接口之后,我们要求 Retrofit 创建一个实现,我们可以使用它来针对给定的基本 URL 发出请求。能够切换基本 URL 对集成测试也很有帮助。要生成客户端,代码如下所示:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.nasa.gov")
.addConverterFactory(JacksonConverterFactory.create())
.build();
APODClient apodClient = retrofit.create(APODClient.class);
CompletableFuture<APOD> response = apodClient.getApod("DEMO_KEY");
// do other stuff here while the request is in-flight
APOD apod = response.get();
System.out.println(apod.title);
API 认证
如果我们的接口中有多个方法都需要一个 API 密钥,则可以通过HttpInterceptor在 base 中添加一个来配置它OkHttpClient。可以将自定义客户端添加到Retrofit.Builder. 创建自定义客户端所需的代码是:
private OkHttpClient clientWithApiKey(String apiKey) {
return new OkHttpClient.Builder()
.addInterceptor(chain -> {
Request originalRequest = chain.request();
HttpUrl newUrl = originalRequest.url().newBuilder()
.addQueryParameter("api_key", apiKey).build();
Request request = originalRequest.newBuilder().url(newUrl).build();
return chain.proceed(request);
}).build();
}
构建类来表示远程 API 是一个很好的抽象,可以很好地与依赖注入配合使用,并且让 Retrofit 基于可定制的 OkHttp 客户端为您创建它们非常棒。
如果以上都不是您想要的,请查看以下建议:
REST Assured - 专为测试您的 REST 服务而设计的 HTTP 客户端。提供用于发出请求的流畅界面和用于对响应进行断言的有用方法。
cvurl - Java 11 HttpClient 的包装器,它使您在发出复杂请求时可能会遇到一些尖锐的边缘。
Feign - 与 Retrofit 类似,Feign 可以从带注释的接口构建类。Feign 非常灵活,可以通过多种选项来发出和读取请求、指标、重试等等。
Spring RestTemplate(同步)和WebClient(异步)客户端 - 如果您在项目中的其他所有内容中都使用过 Spring,那么坚持使用该生态系统可能是一个好主意。Baeldung 有一篇文章比较它们。
MicroProfile Rest Client - 另一个处于“从带注释的接口构建类”模式的客户端,这个很有趣,因为您也可以重用相同的接口来创建 Web 服务器,并确保客户端和服务器匹配。如果您正在为该服务构建服务和客户端,那么它可能适合您。
你适合学Java吗?4大专业测评方法
代码逻辑 吸收能力 技术学习能力 综合素质
先测评确定适合在学习