唯一一个优雅满分100的Http客户端

导读:本文勇哥从AI时代背景下的软件架构变化谈起,引出其中一个必要的Http客户端技术,进而分析当前Java领域主要的Http客户端和Http框架,并重点阐述了其中优雅度满分的Retrofit框架,以及相关的使用技巧。通过阅读本文,你可以快速了解Java领域的三大Http客户端是什么?三大封装框架是什么?以及熟练掌握Retrofit框架的各种使用技巧。

前沿

在AI技术日新月异的今天,软件架构正经历着前所未有的变革,以适应更加复杂、高效且智能的数据交互需求。作为这一变革中的重要一环,HTTP客户端技术成为了连接前后端、大模型与Java、微服务之间不可或缺的桥梁。在Java这一广泛应用的编程语言中,HTTP客户端的选择与使用不仅关乎到系统的性能与稳定性,还直接影响到开发效率与代码的可维护性。因此对于开发者掌握好Http客户端和框架势必重要!

三大框架是什么?

在Java生态中,三大主流的HTTP客户端分别是:

  • Apache HttpClient:作为Apache软件基金会下的一个项目,HttpClient以其丰富的功能、高度的可配置性和广泛的社区支持而闻名。它支持HTTP/1.1和HTTP/2协议,提供了强大的请求执行、响应处理以及连接管理功能。

  • OkHttp:由Square公司开发,OkHttp以其高效、易用和强大的错误处理能力而受到青睐。它支持同步和异步请求,内置了连接池、GZIP压缩和HTTP/2等特性,非常适合在Android和Java后端服务中使用。

  • HttpUrlConnection:随着Java 11的发布,Java平台内置了一个全新的HTTP客户端API。这个API旨在提供简单、现代的HTTP客户端功能,同时保持与Java平台的紧密集成。它支持HTTP/2和WebSocket,并提供了异步和流式API,使得处理HTTP请求变得更加灵活和高效。

这三大客户端封装实现了HTTP协议,但是在封装的API方法上千差万别,且都不怎么好用,因此开源社区又陆续的出现了三大HTTP框架:

  • Spring RestTemplate(尽管Spring 5引入了WebClient作为更现代的替代品,但RestTemplate在旧项目中仍广泛使用):RestTemplate是Spring框架提供的一个同步客户端,用于简化与HTTP服务的通信。它提供了丰富的模板方法,用于处理HTTP请求,并自动将响应体绑定到Java对象上。

  • Retrofit(注意:虽然Retrofit在Android开发中非常流行,但严格来说它更多被用于Android而非纯Java后端环境。不过,其设计理念和优雅度值得借鉴):Retrofit是一个类型安全的HTTP客户端,用于Android和Java,它基于OkHttp构建,通过注解的方式极大地简化了HTTP请求的编写。Retrofit将HTTP请求抽象为Java接口,开发者只需定义接口方法并添加注解,即可实现复杂的HTTP请求。

  • Feign:Feign是一个声明式的Web服务客户端,它使得编写Web服务客户端变得更加简单。Feign通过创建接口和注解的方式来定义服务绑定,它内部封装了Ribbon和Hystrix,提供了负载均衡和断路器功能,非常适合在微服务架构中使用。

企业开发者往往都使用更为简单的框架,而这3大框架都为主流的,但是他们各自有很明显的区别:

  • RestTemplate:Spring把HttpClient、OkHttp、HttpUrlConnection的使用统一成一套API,只做了统一,并API使用上并没有简化太多

  • Retrofit:采用声明式方式定义http请求,使得调用http请求变成了对方法进行调用,非常优雅的方式供开发者使用

  • Feign:同Retrofit一样,采用声明式的方式定义http请求,但多用于微服务之间通信

在实践开发中,如果开发的是微服务项目则可首选Feign,因为它还支持更多微服务所需要的功能。而如果在单体项目中则首选Retrofit,其优雅的使用方式能大大简化接口的开发、管理。同时Retrofit底层通过OkHttp进行实现,性能相比其它框架最好。

Retrofit框架是什么?

官网:Retrofit

Retrofit基于OkHttp开发的、类型安全的Android或Java Http框架。再此我们选用Retrofit框架的重点理由是它基于OkHttp封装,性能好,同时它融入了流行的声明式(PS:只需要定义,不需要实现)开发思想,便于我们开发和学习。

Retrofit入门

在Retrofit中要实现一个Http请求总体来说共有以下2个步骤:

  • 1、导入依赖

  • 2、声明API

  • 3、生效API

导入依赖

 <dependency>
     <groupId>com.squareup.retrofit2</groupId>
     <artifactId>retrofit</artifactId>
     <version>2.11.0</version>
 </dependency>

声明API

我们可以先创建一个接口类:cn.itcast.star.graph.comfyui.client.api.ComfyuiApi,并按如下代码进行编写:

package cn.itcast.star.graph.comfyui.client.api;
 ​
 import retrofit2.Call;
 import retrofit2.http.GET;
 ​
 import java.util.HashMap;
 ​
 public interface ComfyuiApi {
 ​
     /**
      * 获取系统信息
      * @return
      */
     @GET("/system_stats")
     Call<HashMap> getSystemStats();
 ​
 }

使用Retrofit来声明API,其实就是声明接口方法,比如上述类中定义了一个方法getSystemStats:

  • 方法名可以任意取,但建议与http接口名称一致

  • 方法通过@GET注解声明当前请求方式是GET并且请求的地址为/system_stats,即获取Comfyui的系统信息接口

  • 方法返回结果为Call<HashMap>对象

    • Call是固定的返回对象

    • HashMap则是接口返回的数据自动转成Map集合存储

生效API

上面声明类要生效,我们还需要配置生效,可创建一个配置类:cn.itcast.star.graph.comfyui.client.config.ComfyuiConfig

package cn.itcast.star.graph.comfyui.client.config;
 ​
 import cn.itcast.star.graph.comfyui.client.api.ComfyuiApi;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import retrofit2.Retrofit;
 import retrofit2.converter.jackson.JacksonConverterFactory;
 ​
 import java.io.IOException;
 ​
 @Configuration
 public class ComfyuiConfig {
 ​
     @Bean
     public ComfyuiApi comfyuiApi() throws IOException {
         Retrofit retrofit = new Retrofit.Builder()
                 .baseUrl("http://192.168.100.129:8188")
                 .addConverterFactory(JacksonConverterFactory.create())
                 .build();
         ComfyuiApi comfyuiApi = retrofit.create(ComfyuiApi.class);
         return comfyuiApi;
     }
 ​
 }

在类中:

  • 首先通过Retrofit.Builder构建一个Retrofit客户端

    • 通过baseUrl指定请求的服务器地址

    • 通过addConverterFactory指定请求数据的转换器

  • 最后调用 retrofit.create方法创建ComfyuiApi接口的实现

通过上述代码,在Spring IOC中就是声明好了一个可以远程调用获取Comfyui服务器状态的Bean.

测试API

在测试包下创建类:cn.itcast.star.graph.ComfyuiApiTest

 package cn.itcast.star.graph;
 ​
 import cn.itcast.star.graph.comfyui.client.api.ComfyuiApi;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 ​
 @SpringBootTest
 public class ComfyuiApiTest {
 ​
    @Autowired
    ComfyuiApi comfyuiApi;
 ​
    @Test
    public void test() throws Exception {
        System.out.println(comfyuiApi.getSystemStats().execute().body());
    }
 ​
 }

在类中,直接注入ComfyuiApi,并调用getSystemStats(),即可发起请求并打印出结果:

Retrofit 注解大全

Retrofit为了应对更复杂的Http请求,提供了丰富的注解来支持:

  • @Query:用来声明http查询部分的参数,与@RequestParam类似

  • @Path:用于说明请求路径参数,与@PathVariable类似

     @GET("group/{id}/users")
     Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort);
  • @Body:用于声明请求体对象,与@RequestBody类似

    @POST("users/new")
     Call<User> createUser(@Body User user);
  • @Multipart:用于说明当前请求以表单形式发起,常常用于带有文件的接口

    • 如果是文件字段需要使用 MultipartBody.Part

    • 如果是非文件字段需要使用 RequestBody

  • @Part:用于说明一个表单字段

    @Multipart
     @PUT("user/photo")
     Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);
  • @Headers:设定请求头信息

    @Headers({
         "Accept: application/vnd.github.v3.full+json",
         "User-Agent: Retrofit-Sample-App"
     })
     @GET("users/{username}")
     Call<User> getUser(@Path("username") String username);
  • @Header:设定一个头字段

    @GET("user")
    Call<User> getUser(@Header("Authorization") String authorization)
  • @HeaderMap :把一个Map内容设定到请求头中

    @GET("user")
    Call<User> getUser(@HeaderMap Map<String, String> headers)

Retrofit 高级配置

日志开启

Retrofit还提供了打印日志的功能,方便我们进行BUG的排错。Retrofit日志功能默认是关闭的,可以通过以下代码进行开启:

@Bean
public ComfyuiApi comfyuiApi() throws IOException {
    HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
    loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

    OkHttpClient okHttpClient = new OkHttpClient.Builder()
        .addInterceptor(loggingInterceptor)
        .retryOnConnectionFailure(true)
        .connectTimeout(30, TimeUnit.SECONDS)
        .build();

    Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("http://192.168.100.129:8188")
        .client(okHttpClient)
        .addConverterFactory(JacksonConverterFactory.create())
        .build();
    ComfyuiApi comfyuiApi = retrofit.create(ComfyuiApi.class);
    return comfyuiApi;
}

我们之前提供过Retrofit框架底层是通过OkHttp实现,Retrofit的日志功能也是交由底层OkHttp实现:

  • 由于要重新设置OkHttp,因此代码中自行构建了OkHttpClient

  • 给OkHttpClient增加了日志拦截器HttpLoggingInterceptor,并设置拦截器的日志级别为BODY

    • NONE:不输出

    • BASIC:输出基本摘要

    • HEADERS:输出头信息

    • BODY:输出body数据

  • 最后第14行通过client方法,重新设定Retrofit底层使用的OkHttp客户端

按上述代码进行修改后,重新运行ComfyuiApiTest类,即可在控制台看见相关的日志输出:

修改数据转换器

Retrofit支持把Http的数据直接转换成各种对象、各种数据格式,要使用那种格式,可通过配置数据转换器自行选择,目前Retrofit支持8种:

  • Gson: com.squareup.retrofit2:converter-gson

  • Jackson: com.squareup.retrofit2:converter-jackson

  • Moshi: com.squareup.retrofit2:converter-moshi

  • Protobuf: com.squareup.retrofit2:converter-protobuf

  • Wire: com.squareup.retrofit2:converter-wire

  • Simple XML: com.squareup.retrofit2:converter-simplexml

  • JAXB: com.squareup.retrofit2:converter-jaxb

  • Scalars (primitives, boxed, and String): com.squareup.retrofit2:converter-scalars

在项目中如果要使用GSON,则先需要导入对应的依赖:

<dependency>
    <groupId>com.squareup.retrofit2</groupId>
    <artifactId>converter-gson</artifactId>
    <version>2.11.0</version>
</dependency>

然后在代码中通过addConverterFactory方法进行,设定转换工厂类:

工厂类命令为XXXConverterFactory,如果是Jackson则为JacksonConverterFactory,以此类推。

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .addConverterFactory(GsonConverterFactory.create())
    .build();

GitHubService service = retrofit.create(GitHubService.class);

勇哥最新力作剧透——Java+AI前沿技术

🔥【Java+AI燃爆新项目】“星图”剧透来袭!🌟 解锁Stable Diffusion、ComfyUI、Ollama等前沿科技,融合Retrofit2与双端异步通信,还有集群队列调度的智慧加成!🚀 想掌握AI应用的核心竞争力吗?快来围观我们的课程项目,一起打造未来科技的璀璨之星!✨ 👀别错过,关注勇哥,开启你的AI学习新篇章!📚

Java+AIGC项目剧透——星图

​​

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

miukoo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值