美丽的神话 发表于 2024-5-12 15:20:49

求求你别再用OkHttp调用API接口了,快来试试这款HTTP客户端库吧

引言

在一样平常业务开辟中,我们时常必要使用一些其他公司的服务,调用第三方体系的接口,这时就会涉及到网络请求,通常我们可以使用HttpClient,OkHttp等框架去完成网络请求。随着RESTful API的遍及,一个高效、简洁且易于维护的HTTP客户端库显得尤为关键。而本文主要先容一款强大的网络客户端库:Retrofit2。
Retrofit2简介

Retrofit2是什么?

Retrofit2是一个由Square公司精心打造并开源的Java与Android双平台适用的RESTful API客户端库,其核心构建在性能卓越的OkHttp库之上。通过精巧的设计原理,Retrofit2将原本复杂的HTTP网络请求过程高度抽象为直观且类型安全的接口调用模式,从而极大地简化了应用程序与后端API之间的交互逻辑。
开辟者使用Retrofit2能够以注解驱动的方式来声明和定义API接口,轻松指定HTTP方法、URL路径以及请求参数等关键信息,进而自动生成相应的请求实当代码。该框架不仅支持同步及异步两种调用方式,还内置了对JSON数据序列化和反序列化的自动化处理能力,这意味着无论是发送请求还是解析相应,都能无缝转换成或从对应的Java对象进行操作。
此外,Retrofit2具备强大的扩展性,允许开辟人员根据项目需求定制各种高级功能,如自定义转换器以适应不同数据格式,添加拦截器以实现全局请求/相应处理,以及集成多种认证机制,充分满足当代应用程序中面对复杂网络环境的各种需求。
Retrofit2能做什么?

Retrofit2的主要功能包括:

[*]类型安全API设计:Retrofit2赋予开辟者以声明式接口定义的方式来确保网络请求的类型安全性。这意味着通过在接口方法上使用注解来精确指定HTTP请求参数和相应数据布局,框架会自动进行类型校验并确保数据在传输过程中严格符合预期类型,从而消除类型不匹配引发的运行时错误。
[*]网络请求流程精简:Retrofit2极大地简化了发起网络请求的步调。开辟人员仅需专注于设计与后端服务交互的API接口及相应的HTTP动作,框架会自动生成底层逻辑代码,无需手动编写创建请求、设置Header或解析相应内容等繁琐环节,极大地进步了开辟效率。
[*]内置数据转换机制:为便于数据处理,Retrofit2集成了多种数据转换器(Converter),能够轻松地将从服务器接收到的HTTP原始数据流转换成Java对象,支持常见的数据格式如JSON、XML以及其他可通过扩展实现的格式,这使得数据模子与现实业务逻辑之间的映射变得直观且易于管理。
[*]异步实验与回调集成:针对移动应用中避免阻塞UI线程的需求,Retrofit2全面支持异步网络请求。它允许开辟者采用回调函数或者联合RxJava等反应式编程库来优雅地处理异步任务,确保即便在网络请求实验期间也能保持流畅的用户体验和应用性能。
Retrofit2的优点


[*]代码简化与一致性:通过提供一种声明式的方式来设计和实现网络请求接口,Retrofit2极大地减少了开辟人员在处理网络通讯时所需编写的重复性代码量。开辟者仅需关注业务逻辑相干的API描述,无需手动构建和管理复杂的HTTP请求。
[*]提拔可读性和维护性:框架夸大清晰的布局和注解驱动的配置方式,使得网络请求逻辑更加直观且易于理解,进而进步了代码的可读性和维护性。开辟者能够快速识别并定位各个网络操作的意义和行为。
[*]类型安全保证:通过集成类型安全的API设计,Retrofit2消除了因参数拼写错误或类型不匹配所引发的运行时非常风险。它确保了数据互换过程中参数类型的正确性,增强了应用的团体健壮性。
[*]高效稳定集成:Retrofit2无缝集成了高性能的OkHttp库,充分使用了其在网络连接复用、缓存策略、失败重试等方面的性能优势,从而有效提拔了网络请求的实验效率及服务稳定性,为应用程序提供了更强大的网络支持基础架构。
Retrofit2 VS HttpClient


[*]当代化的 API 设计:
Retrofit2 使用当代编程风格,通过注解定义HTTP请求接口,代码简洁易读。相比之下,HttpClient必要手动构建Request和处理相应,代码布局更为繁琐。
[*]自动转换数据:
Retrofit2 提供了内置或自定义的数据转换器,如 GsonConverterFactory,可以自动将JSON或其他格式的数据转换为 Java对象,简化了数据的序列化和反序列化过程。HttpClient则必要手动处理数据转换,操作相对繁琐。
[*]异步与同步支持:
Retrofit2 支持同步和异步两种网络请求方式,提供了基于Call或 Observable等类型的异步调用方式,方便联合 RxJava等相应式编程框架使用,极大地提拔了用户体验和应用程序性能。HttpClient在异步支持方面较为局限。
[*]面向接口编程:
Retrofit2 通过定义服务接口来描述API端点,使得网络层与其他业务逻辑解耦,进步了代码组织性和可测试性。相比之下,HttpClient直接操作 HttpRequest和HttpResponse实例,耦合度较高。
[*]兼容性与性能:
官方不再推荐使用Apache HttpClient,而OkHttp(Retrofit2 底层依赖库)经过持续优化,在性能、连接复用、缓存策略以及对HTTP/2协议的支持等方面表现更优。
[*]易于扩展:
Retrofit2可以很容易地添加拦截器(Interceptor)进行诸如身份验证、日志记录和重试机制等功能的扩展。固然]HttpClient的扩展性也很强,但必要更多手工编码。
[*]社区活泼与更新频仍:
Retrofit2和OkHttp 社区活泼,更新迭代较快,能快速跟进新的技术和最佳实践,确保开辟者能够使用最新的技术改进和安全更新。
Retrofit2 在简化RESTful API客户端开辟、进步效率、易用性、可维护性以及对当代网络特性的支持上均优于旧版的 HttpClient。
Retrofit2 VS OkHttp


[*]API 接口定义简洁明了:
Retrofit2 使用注解(Annotations)来描述 HTTP 请求方法、URL、参数等,开辟者只需通过定义 Java 接口就能清晰地表达出网络调用的意图。相比之下,OkHttp 必要开辟者直接处理复杂的 HTTP 请求构建逻辑。
[*]自动序列化与反序列化:
Retrofit2 提供了转换器(Converter)支持,如 GsonConverterFactory、JacksonConverterFactory 等,能够自动将 JSON 或其他格式的数据转换为 Java 对象以及相反的操作,极大地简化了数据处理过程。而 OkHttp 必要开辟者手动处理数据转换。
[*]同步/异步模式同一处理:
Retrofit2 不仅支持同步请求,还对异步请求提供了同一的 Call 或 Observable 返回类型,方便在 Android 中进行非阻塞式编程,并且易于联合 RxJava 等相应式库使用。相比之下,OkHttp 的异步请求处理必要开辟者自行管理。
[*]丰富的注崩溃系:
Retrofit2 提供了多种注解以支持不同的请求类型(GET、POST、PUT、DELETE 等)、路径参数、查询参数、表单提交、文件上传、多部分请求等,可以机动配置请求内容。而 OkHttp 的使用必要开辟者手动构建请求参数和处理相应。
[*]强大的扩展性:
Retrofit2 支持自定义拦截器(Interceptor),可以在请求前后添加额外的业务逻辑,如认证、日志记录、缓存策略等。同时,可以自由配置 OkHttpClient 实例,充分使用 OkHttp 的所有特性,如连接池、重试机制、HTTP/2 支持等。相比之下,OkHttp 更专注于网络通讯的核心功能。
[*]代码可读性强:
Retrofit2 将网络请求抽象成一个服务接口的形式,使得代码更易于阅读和维护,进步了团体项目的组织性和整洁度。相比之下,OkHttp 的使用必要开辟者更多地关注底层的网络通讯细节。
[*]降低耦合度:
使用 Retrofit2 可以将网络访问层与应用的其他组件更好地解耦,使得业务逻辑代码更加关注于处理业务自己,而不是如何发起网络请求。相比之下,OkHttp 的使用必要开辟者更多地处理网络请求的细节,耦合度较高。
固然 OkHttp 是一个高性能的 HTTP 客户端,专注于网络通讯的核心功能,但 Retrofit2 在此基础上封装了一层高级抽象,让开辟者能以声明式的方式编写网络请求代码,降低了复杂度并提拔了开辟效率。
Retrofit2使用

引入依赖

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


<dependency>
        <groupId>com.squareup.retrofit2</groupId>
        <artifactId>converter-jackson</artifactId>
        <version>2.9.0</version>
</dependency>定义API接口

在Retrofit框架中,构建与服务器的通讯接口是通过定义清晰、布局化的API接口来实现的。这个过程涵盖了详细指定请求方式、路径以及相干参数等关键信息。具体来说,每个接口方法代表了一种特定的HTTP交互模式,明确指示了请求类型(如GET、POST、PUT或DELETE)和目标URL路径。
请求方法

在接口方法上应用诸如 @GET、@POST、@PUT 和@DELETE等注解是为了精确映射到相应的HTTP动作。
@POST("user/add")

@GET("user/info/{id}")

// 也可以指定查询参数
@GET("user/list?pageSize=50")URL操作

使用@Path、@Query和@Body注解能够进一步细化接口描述,分别用于设定路径中的动态变量、查询字符串参数以及HTTP请求体内容。接口方法可以接受不同类型的参数,这些参数会根据注解类型被正确地插入到请求的不同部分。
使用@Path 注解的参数会在现实调用时将传入值插入到URL路径中相应的位置
@GET("group/{id}/users")
Call<List<UserInfoResponse>> groupList(@Path("id") int groupId);还可以通过@Query参数添加查询参数。
@GET("group/{id}/users")
Call<List<UserInfoResponse>> groupList(@Path("id") int groupId, @Query("pageSize") Integer pageSize);对于复杂的查询参数组合,可以使用Map。
@GET("group/{id}/users")
Call<List<UserInfoResponse>> groupList(@Path("id") int groupId, @QueryMap Map<String, String> options);请求体

对于请求对象,可以使用@Body注解指定对象作为HTTP请求体。@Body注解通常用于指定将对象作为JSON格式的数据传输到服务器。当您在 Retrofit 接口方法中使用 @Body注解时,Retrofit将会使用内部的转换器(如GsonConverter 或者 JacksonConverter)将对象转换为JSON 格式的字符串,并将其作为请求的请求体发送到服务器。
通常情况下,@Body注解用于POST 或者PUT请求,此中请求的主体包含了要传输的对象的JSON表现形式。
@POST("users/new")
Call<UserInfoResponse> createUser(@Body UserInfoRequest user);通常情况下 @Body注解用于指定JSON格式的数据传输,但Retrofit并不会强制要求请求体的格式必须是JSON。您也可以使用其他格式的数据,比方XML或者纯文本,只要在请求体中提供了正确的数据格式,并且服务器能够正确地解析这种格式的数据。
表单数据和Multipart请求

方法还可以声明发送表单数据和多部分请求数据
使用@FormUrlEncoded,@Field或者@FieldMap将发送表单数据。
@FormUrlEncoded
@POST("users/new")
Call<UserInfoResponse> createUser1(@Field("name") String name, @Field("passowrd") String password);

@FormUrlEncoded
@POST("users/new")
Call<UserInfoResponse> createUser2(@FieldMap Map<String, Object> paramMap);同时他还支持发送多部分请求,比方文件上传。在方法上使用@Multipart注解用于发送多部分请求,而参数要使用@Part注解。在Retrofit接口方法中使用@Multipart注解时,Retrofit将会使用multipart/form-data格式来发送请求,这种格式允许同时上传文本数据和二进制文件数据。
@Multipart
@POST("user/image")
Call<UserInfoResponse> updateUser(@Part("image") RequestBody userImage, @Part("imageDesc") RequestBody imageDesc);@Part注解用于声明每个部分的内容,此中可以是RequestBody类型的文本或者二进制数据,也可以是MultipartBody.Part类型的文件或者其他二进制数据。如许的话,就可以通过多个@Part注解来声明不同类型的部分,以满足不同的上传需求
Header信息

使用@Headers注解为方法设置静态头部。
@Headers({"Accept: application/json, text/plain, */*","User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36","Cookie:xxxxxx"})@POST("users/new")
Call<UserInfoResponse> createUser(@Body UserInfoRequest user);使用用@Header或者HeaderMap注解动态更新请求头。必须提供相应的参数给@Header。假如值为 null,则头部将被省略。否则,将对值调用toString,并使用效果。
@POST("users/new")
Call<UserInfoResponse> createUser(@Header("Cookie") String cookie, @Body UserInfoRequest user);

@POST("users/new")
Call<UserInfoResponse> createUser2(@HeaderMap Map<String, String> headerMap, @Body UserInfoRequest user);关于Header参数,我们还可以通过OkHttp的拦截器进行操作。
方法返回值

API接口方法通常返回 Call 类型的对象,这里的T代表期望从服务器接收的数据类型。这种方式使得开辟者能方便地使用 Retrofit 提供的回调机制或其他相应式编程库(如RxJava)来处理网络请求的效果,从而确保了对异步操作的良好控制和管理。
public interface MyClientService {
    @POST("test/add")
    Call<TestResponse> addTest(@Body TestRequest testRequest);

        @GET("group/{id}/users")
        Call<List<User>> groupList(@Path("id") int groupId);
}创建Retrofit实例

Retrofit框架的核心组件是Retrofit实例。Retrofit实例作为整个框架的心脏,不仅负责搭建网络请求所需的基础办法,还承担起发起请求、转换数据和管理相应生命周期的任务。
Retrofit retrofit = new Retrofit.Builder()
                                // 设置 API 的基础 URL
                .baseUrl("http://localhost:8080/coderacademy/")
                .addConverterFactory(JacksonConverterFactory.create())
                .build();baseUrl设置

此中baseUrl用于指定请求服务器的根地址或者API的基础路径。Retrofit会自动将baseUrl和方法注解中的相对路径联合起来生成现实请求的完整URL。比方对上述示例中:
public interface MyClientService {
    @POST("test/add")
    Call<TestResponse> addTest(@Body TestRequest testRequest);
}最终的请求url为:localhost:8080/coderacademy/test/add。
关于baseUrl的设置有一些注意事项:

[*]baseUrl设置必须以/结尾,否则汇报错。
https://coderacademy.oss-cn-zhangjiakou.aliyuncs.com/blogcontent/20240221172931.png
[*]请求方法中的相对路径(不以"/"开头),将会正确附加在以斜杠结尾的 baseUrl 的路径后面。这确保了正确的 URL 效果。如baseUrlhttp://localhost:8080/coderacademy/, 方法url为test/add,则最终的路径为:localhost:8080/coderacademy/test/add。
[*]请求方法中的绝对路径(以"/"开头),忽略baseUrl中的路径组件,只保存host部分,最终的URL将只包含baseUrl的主机部分和方法的路径。如baseUrlhttp://localhost:8080/coderacademy/, 方法url为/test/add,则最终的路径为:localhost:8080/test/add。
[*]请求方法中的路径可以是完整的URL,假如方法路径是完整的URL,则会替换baseUrl。如baseUrl为http://localhost:8080/coderacademy/,而方法url为http://localhost:8081/coderacademy/test/add,则最终的url为:http://localhost:8081/coderacademy/test/add。
Converter设置

Retrofit默认只能将HTTP相应主体反序列化为OkHttp的ResponseBody类型,并且只能接受其RequestBody类型用于@Body注解。为了支持其他类型,可以添加转换器。
官方提供了8种转换器:
转换器功能使用依赖Gson将 JSON 数据转换为 Java 对象,以及将 Java 对象转换为 JSON 数据。com.squareup.retrofit2:converter-gsonJackson将JSON数据转换为 Java 对象,以及将 Java 对象转换为 JSON 数据。com.squareup.retrofit2:converter-jacksonMoshi将 JSON 数据转换为 Java 对象,以及将 Java 对象转换为 JSON 数据。com.squareup.retrofit2:converter-moshiProtobuf将 Protocol Buffers 数据转换为 Java 对象,以及将 Java 对象转换为 Protocol Buffers 数据。com.squareup.retrofit2:converter-protobufWire将 Wire 数据转换为 Java 对象,以及将 Java 对象转换为 Wire 数据。com.squareup.retrofit2:converter-wireSimple XML将 XML 数据转换为 Java 对象,以及将 Java 对象转换为 XML 数据。com.squareup.retrofit2:converter-simplexmlJAXB将 XML 数据转换为 Java 对象,以及将 Java 对象转换为 XML 数据。com.squareup.retrofit2:converter-jaxbScalars将原始类型、包装类型和字符串转换为 RequestBody,以及将 ResponseBody 转换为原始类型、包装类型和字符串。com.squareup.retrofit2:converter-scalars除了官方提供的这几种转换器以外,假如使用了Retrofit默认不支持的内容格式的API 进行通讯(比方YAML、TXT、自定义格式),或者使用不同的库来实现现有格式(请求与相应是不同的格式),我们也可以实现自定义转换器。除此之外Retrofit还可以跟OkHttpClient搭配使用,实现其高级功能,通过 OkHttpClient,您可以实现诸如网络连接池、超时设置、重试机制、拦截器等高级功能。而Retrofit则提供了简化的API,使得使用这些高级功能变得更加方便。
OkHttpClient okHttpClient = new OkHttpClient.Builder()
    .connectTimeout(30, TimeUnit.SECONDS) // 设置连接超时时间
    .readTimeout(30, TimeUnit.SECONDS)    // 设置读取超时时间
    .writeTimeout(30, TimeUnit.SECONDS)   // 设置写入超时时间
    .addInterceptor(new LoggingInterceptor()) // 添加日志拦截器
    .build();

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("http://localhost:8080/coderacademy/")
    .client(okHttpClient) // 设置自定义的 OkHttpClient
    .addConverterFactory(GsonConverterFactory.create())
    .build();创建请求接口实例,发起请求

在创建完Retrofit实例之后,接下来就必要通过调用Retrofit实例的create() 方法来创建API接口的实例。然后就可以使用该实例调用定义在接口中的方法来发起网络请求。
MyClientService myClientService = retrofit.create(MyClientService.class);

TestRequest testRequest = new TestRequest();
testRequest.setName("码农Academy");
testRequest.setPassword("12131");
// 发起请求
Call<TestResponse> call = myClientService.addTest(testRequest);
try {
        Response<TestResponse> response = call.execute();
        System.out.println("是否请求成功:"+response.isSuccessful());
        System.out.println("响应:"+ response.toString());
        TestResponse testResponse = response.body();
        System.out.println("请求结果:"+ testResponse.toString());
}catch (Exception e){
        e.printStackTrace();
}在Retrofit中,Call对象代表了一个待实验的网络请求。它是一个表现单个异步或同步实验的请求的对象。Call接口定义了实验网络请求和处理相应的方法。Call接口的泛型类型参数表现了该网络请求的相应类型。比方,Call 表现该网络请求的相应是一个TestResponse对象相应。
execute()方法用于同步实验网络请求,并返回一个Response对象。当调用execute()方法时,请求将立即发出,当前线程将被阻塞直到请求完成并返回相应。Response对象包含了网络请求的相应数据,可以通过调用body()方法来获取相应主体。
另外,还可以使用Call对象来发起异步网络请求。异步请求允许您在发出请求后继续实验其他代码,而不必等待网络请求完成。当请求完成后,Retrofit将在后台线程上调用您提供的回调方法,以处理相应数据。
Call<TestResponse> call = myClientService.addTest(testRequest);

try {
        call.enqueue(new Callback<TestResponse>() {
                @Override
                public void onResponse(Call<TestResponse> call, Response<TestResponse> response) {
                        System.out.println("是否请求成功:"+response.isSuccessful());
                        System.out.println("响应:"+ response.toString());
                        TestResponse testResponse = response.body();
                        System.out.println("请求结果:"+ testResponse.toString());
                }

                @Override
                public void onFailure(Call<TestResponse> call, Throwable t) {
                        // 请求失败结果
                }
        });
   
}catch (Exception e){
        e.printStackTrace();
}异步请求时,必要实现Callback接口,该接口定义了处理乐成和失败相应的方法。在 onResponse方法中处理乐成相应,在onFailure方法中处理失败相应。
然后使用Call对象的enqueue()方法来实验异步网络请求,并传入Callback。Retrofit将在后台线程上实验网络请求,并在请求完成后调用相应的回调方法。
到此一个使用Retrofit2发起请求的功能就完成了。接下来我们看一下Retrofit2的一些高级功能。
Retrofit2的高级功能

拦截器

Retrofit的高级功能通常必要与OkHttpClient联合使用才能实现。OkHttpClient是一个强大的HTTP客户端库,Retrofit是基于它构建的,并且Retrofit默认使用 OkHttpClient作为其底层的网络请求库。
通过OkHttpClient,您可以实现诸如网络连接池、超时设置、重试机制、拦截器等高级功能。而Retrofit则提供了简化的API,使得使用这些高级功能变得更加方便。
OkHttpClient okHttpClient = new OkHttpClient.Builder()
    .connectTimeout(30, TimeUnit.SECONDS) // 设置连接超时时间
    .readTimeout(30, TimeUnit.SECONDS)    // 设置读取超时时间
    .writeTimeout(30, TimeUnit.SECONDS)   // 设置写入超时时间
    .addInterceptor(new LoggingInterceptor()) // 添加日志拦截器
    .build();

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("http://localhost:8080/coderacademy/")
    .client(okHttpClient) // 设置自定义的 OkHttpClient
    .addConverterFactory(GsonConverterFactory.create())
    .build();对于拦截器,在现实开辟中有较多必要使用的场景,比如第三方服务必要使用一些签名验证手段,请求数据进行加密等,我们都可以同一在拦截器中进行处理。自定义拦截器,我们必要实现Interceptor接口,实现intercept()方法。
@Slf4j
public class MyAuthInterceptor implements Interceptor {
   
    @NotNull
    @Override
    public Response intercept(@NotNull Chain chain) throws IOException {

      String appKey = "MyKey";
      String appToken = "MyToken";

      Request request = chain.request();
      Request.Builder builder = request.newBuilder();
      builder.addHeader("Api-Key", appKey).addHeader("Api-Secret", appToken);
      request = builder.build();
      return chain.proceed(request);
    }
}传入拦截器:
OkHttpClient okHttpClient = new OkHttpClient.Builder()
    .connectTimeout(30, TimeUnit.SECONDS) // 设置连接超时时间
    .readTimeout(30, TimeUnit.SECONDS)    // 设置读取超时时间
    .writeTimeout(30, TimeUnit.SECONDS)   // 设置写入超时时间
    .addInterceptor(new LoggingInterceptor()) // 添加日志拦截器
    .addInterceptor(new MyAuthInterceptor())
    .build();转换器

前面内容已经提到对于转换器,出了Retrofit2提供的8种转换器以外,有些特别的请求体这几种转换器不能满足,此时,我们可以自定义转换器。必要继承Converter.Factory类,重写requestBodyConverter与reponseBodyConverter方法即可。
public class CustomBodyConverterFactory extends Converter.Factory {    @Nullable    @Override    public Converter responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {      return new CustomResponseBodyConverter(type);    }    @Nullable    @Override    public Converter
页: [1]
查看完整版本: 求求你别再用OkHttp调用API接口了,快来试试这款HTTP客户端库吧