OkHttp:更加优雅的客户端OkHttps

257 阅读3分钟

上文中,我们介绍了OkHttp的一些常见的用法,以及对其API进行了一些便于调用的封装。而笔者在深入学习的过程中发现了一个基于Lambda表达式、链式调用进行封装的OkHttps,使其的调用方式更加的优雅、简介。

简介 ok.zhxu.cn/v4/introduc… OkHttps 是 2020 年开源的对 OkHttp3 轻量封装的框架,它独创的异步预处理器,特色的标签,灵活的上传下载进度监听与过程控制功能,在轻松解决很多原本另人头疼问题的同时,设计上也力求纯粹与优雅。

Maven中要想使用OkHttps,我们需要引入一个OkHttps核心包和一个OkHttps-xxxx(序列化框架)的序列化包,比如FastJson2,我们可以通过 cn.zhxu okhttps 4.0.0 cn.zhxu okhttps-fastjson2 4.0.0

如果是Jackson的话,我们只需要将fastjson2换成 cn.zhxu okhttps-jackson 4.0.0 即可。

基本使用

首先,我们需要向使用OkHttp那样,构建一个HTTP请求, 为了使用方便,我们更愿意指定一个BaseUrl和MsgConverter: HTTP http = HTTP.builder() .baseUrl("api.example.com") // GsonMsgConverter源自okhttps-gons包中,使用时更换为实际导入的序列化包 .addMsgConvertor(new GsonMsgConvertor()) .build();

随后,我们可以通过链式调用的方式来开始一个同步请求了: List users = http.sync("/users") // api.example.com/users .get() // GET请求 .getBody() // 获取响应报文体 .toList(User.class); // 得到目标数据 或者是一个异步请求: http.async("/users/1") // api.example.com/users/1 .setOnResponse((HttpResult res) -> { // 得到目标数据 User user = res.getBody().toBean(User.class); }) .get(); // GET请求 如果你想要一个WebSocket通讯的话,可以这样: http.webSocket("/chat") .setOnOpen((WebSocket ws, HttpResult res) -> { ws.send("向服务器问好"); }) .setOnMessage((WebSocket ws,Message msg) -> { // 从服务器接收消息(自动反序列化) Chat chat = msg.toBean(Chat.class); // 相同的消息发送给服务器(自动序列化 Chat 对象) ws.send(chat); }) .listen(); // 启动监听

请求三部曲 对于任何请求,OkHttps都可以将其看作为三个步骤:

  1. 确定请求方式(同步、异步)
  2. 构建请求任务(添加请求参数、设置回调函数)
  3. 调用请求方法(get、post、delete、put) 而对于这种模板化的开发方式,作为IDEA的开发者我们可以通过Live Template来提高我们的开发效率:

注入配置 OkHttps还支持通过SPI的方式注入自定义配置类

第一步:新建一个配置类实现cn.zhxu.okhttps.Config接口 package com.example.okhttps;

import cn.zhxu.okhttps.Config; import cn.zhxu.okhttps.HTTP;

public class OkHttpsConfig implements Config {

@Override
public void with(HTTP.Builder builder) {
    // 在这里对 HTTP.Builder 做一些自定义的配置
    builder.baseUrl("https://api.domo.com");
    // 如果项目中添加了 okhttps-fastjson 或 okhttps-gson 或 okhttps-jackson 依赖
    // OkHttps 会自动注入它们提供的 MsgConvertor 
    // 所以这里就不需要再配置 MsgConvertor 了 (内部实现自动注入的原理也是 SPI)
    // 但如果没有添加这些依赖,那还需要自定义一个 MsgConvertor
    builder.addMsgConvertor(new MyMsgConvertor());
}

} 第二步:在项目的/src/main/目录下新建resources/META-INF/services/cn.zhxu.okhttps.Config文件,文件内容是上一个配置类的全类名

为什么要使用SPI注入配置而不是直接给OkHttps设置一个静态变量实例呢? 在一般情况下这样是没问题的,但是某些JVM上(特别是Android)会在某些情况下回收静态变量,而OkHttps的HTTP实例一旦被回收之后,配置都会丢失,导致严重的问题。

对于SpringBoot项目,如果还想要导入application.yml的配置的话,我们可以现在Spring的Bean中加载配置,然后提供静态访问方法,再去配置类中访问这个Bean。 @Component public class ConfigBean {

@Value("${okhttps.baseUrl}")    // 加载配置
private String baseUrl;

private static ConfigBean instance;

public ConfigBean() {
    instance = this;            // 将该 Bean 单例化
}

public static ConfigBean getInstance() {
    return instance;            // 提供静态访问方法
}

// 省略 Getter Seatter

} public class OkHttpsConfig implements Config {

@Override
public void with(HTTP.Builder builder) {
    // 获取 ConfigBean
    ConfigBean confg = ConfigBean.getInstance();
    // 使用配置
    builder.baseUrl(confg.getBaseUrl());
    // 省略其它配置
}

}