# 配置

# 设置 BaseUrl

HTTP http = HTTP.builder()
        .baseUrl("http://api.demo.com")    // 设置 BaseUrl
        .build();
1
2
3

该配置全局生效,在配置了BaseUrl之后,具体的请求便可以省略BaseUrl部分,使得代码更加简洁,例如:

http.sync("/users").get()                  // http://api.demo.com/users

http.sync("/auth/signin")                  // http://api.demo.com/auth/signin
        .addBodyParam("username", "Jackson")
        .addBodyParam("password", "xxxxxx")
        .post();                           // POST请求
1
2
3
4
5
6

在配置了BaseUrl之后,如有特殊请求任务,仍然可以使用全路径的方式,一点都不妨碍:

http.sync("https://www.baidu.com").get();
1

# 回调执行器

OkHttps 默认所有回调都在 IO线程 执行,如何想改变执行回调的线程时,可以配置回调执行器。例如在Android里,让所有的回调函数都在UI线程执行,则可以在构建HTTP时配置如下:

HTTP http = HTTP.builder()
        .callbackExecutor((Runnable run) -> {
            runOnUiThread(run);            // 在UI线程执行
        })
        .build();
1
2
3
4
5

该配置默认 影响所有回调

# 配置 OkHttpClient

与其他封装 OkHttp3 的框架不同,OkHttps 并不会遮蔽 OkHttp3 本身就很好用的功能,如下:

HTTP http = HTTP.builder()
    .config((Builder builder) -> {
        // 配置连接池 最小10个连接(不配置默认为 5)
        builder.connectionPool(new ConnectionPool(10, 5, TimeUnit.MINUTES));
        // 配置连接超时时间(默认10秒)
        builder.connectTimeout(20, TimeUnit.SECONDS);
        // 配置拦截器
        builder.addInterceptor((Chain chain) -> {
            Request request = chain.request();
            // 必须同步返回,拦截器内无法执行异步操作
            return chain.proceed(request);
        });
        // 其它配置: CookieJar、SSL、缓存、代理、事件监听...
    })
    .build();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 并行预处理器

预处理器(Preprocessor)可以让我们在请求发出之前对请求本身做一些改变,但与OkHttp的拦截器(Interceptor)不同:预处理器可以让我们 异步 处理这些问题。

例如,当我们想为请求任务自动添加Token头信息,而Token只能通过异步方法requestToken获取时,这时使用Interceptor就很难处理了,但可以使用预处理器轻松解决:

HTTP http = HTTP.builder()
        .addPreprocessor((PreChain chain) -> {
            HttpTask<?> task = chain.getTask();// 获得当前的HTTP任务
            if (!task.isTagged("Auth")) {      // 根据标签判断该任务是否需要Token
                chain.proceed();
                return;
            }
            requestToken((String token) -> {   // 异步获取 Token
                task.addHeader("Token", token);// 为任务添加头信息
                chain.proceed();               // 继续当前的任务
            });
        })
        .build();
1
2
3
4
5
6
7
8
9
10
11
12
13

Interceptor一样,Preprocessor也可以添加多个。他们之间的区别如下:

拦截器与预处理器的区别

  • 拦截器只能处理同步操作,预处理器支持处理异步操作
  • 拦截器都是并行处理请求,预处理器支持串行处理(详见6.5章节)
  • 拦截器处理时机在请求前和响应后,预处理器只在请求前,并且先于拦截器执行。关于响应后,OkHttps还提供了全局回调监听(详见6.6章节)

# 串行预处理器(TOKEN问题最佳解决方案)

普通预处理器都是可并行处理的,然而有时我们希望某个预处理器同时只处理一个任务。比如 当Token过期时我们需要去刷新获取新Token,而刷新Token这个操作只能有一个任务去执行,因为如果n个任务同时执行的话,那么必有n-1个任务刚刷新得到的Token可能就立马失效了,而这是我们所不希望的。

为了解决这个问题,OkHttps 提供了串行预处理器,它可以让 HTTP 任务排好队,一个一个地进入预处理器:

HTTP http = HTTP.builder()
        .addSerialPreprocessor((PreChain chain) -> {
            HttpTask<?> task = chain.getTask();
            if (!task.isTagged("Auth")) {
                chain.proceed();
                return;
            }
            // 检查过期,若需要则刷新Token
            requestTokenAndRefreshIfExpired((String token) -> {
                task.addHeader("Token", token);            
                chain.proceed();               // 调用此方法前,不会有其它任务进入该处理器
            });
        })
        .build();
1
2
3
4
5
6
7
8
9
10
11
12
13
14

串行预处理器实现了让HTTP任务排队串行处理的功能,但值得一提的是:它并没有因此而阻塞任何线程!

# 全局回调监听

全局回调是实际开发中经常需要的功能,比如对服务器响应的状态码进行统一处理等,同时 OkHttps 的全局回调还具有 回调阻断 的功能:

HTTP http = HTTP.builder()
        .responseListener((HttpTask<?> task, HttpResult result) -> {
            // 所有异步请求(包括 WebSocket)响应后都会走这里

            return true; // 返回 true 表示继续执行 task 的 OnResponse 回调,false 表示不再执行
        })
        .completeListener((HttpTask<?> task, State state) -> {
            // 所有异步请求(包括 WebSocket)执行完都会走这里

            return true; // 返回 true 表示继续执行 task 的 OnComplete 回调,false 表示不再执行
        })
        .exceptionListener((HttpTask<?> task, IOException error) -> {
            // 所有异步请求(包括 WebSocket)发生异常都会走这里

            return true; // 返回 true 表示继续执行 task 的 OnException 回调,false 表示不再执行
        })
        .build();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

全局回调监听与拦截器的异同:

  • 拦截器可以添加多个,全局回调监听分三种,每种最多添加一个
  • 拦截器处的理时机在请求前和响应后,全局回调监听只在响应后,并且晚于拦截器
  • 全局回调监听可以 阻断(return false)某个请求的具体回调,而拦截器不能

# 全局下载监听

HTTP http = HTTP.builder()
        .downloadListener((HttpTask<?> task, Download download) -> {
            // 所有下载在开始之前都会先走这里
            Ctrl ctrl = download.getCtrl();         // 下载控制器
            
        })
        .build();
1
2
3
4
5
6
7