0%

OkHttp | 拦截器(Interceptor)

我的环境如下

  • okhttp3:okhttp:4.7.2

拦截器应用场景


  • 在发送请求前,更改或者添加东西,比如 header 或者 get 的 url 添加「身份认证」

参考资料



内容


回顾一下我们曾经学习过的因特网五层协议栈:

  • 网络请求发出时:应用层->传输层->网络层->连接层->物理层
  • 收到响应后:物理层->连接层->网络层->传输层->应用层

这个很像我们这次要讲的 okhttp 中的 interceptor 的责任链模式。

Interceptor

Application Interceptor

我们可以自定义设置 Okhttp 的拦截器之一。

从流程图中我们可以看到一次网络请求它只会执行一次拦截,而且它是第一个触发拦截的,这里拦截到的url请求的信息都是最原始的信息。所以我们可以在该拦截器中添加一些我们请求中需要的通用信息,打印一些我们需要的日志。

当然我们可以定义多个这样的拦截器,一个处理 header 信息,一个处理 接口请求的 加解密 。

NetwrokInterceptor

NetwrokInterceptor 也是我们可以自定义的拦截器之一。

它位于倒数第二层,会经过 RetryAndFollowIntercptor 进行重定向并且也会通过 BridgeInterceptor 进行 request请求头和 响应 resposne的处理,因此这里可以得到的是更多的信息。在打印结果可以看到它内部重定向操作和失败重试,这里会有比 Application Interceptor 更多的日志。

RetryAndFollowInterceptor

RetryAndFollowUpInterceptor 的作用,看到该拦截器的名称就知道,它就是一个负责失败重连的拦截器。它是 Okhttp 内置的第一个拦截器,通过 while (true)的死循环来进行对异常结果或者响应结果判断是否要进行重新请求。

BridgeInterceptor

BridgeInterceptor 为用户构建的一个 Request 请求转化为能够进行网络访问的请求,同时将网络请求回来的响应 Response 转化为用户可用的 Response。比如,涉及的网络文件的类型和网页的编码,返回的数据的解压处理等等。

CacheInterceptor

CacheInterceptor 根据 OkHttpClient 对象的配置以及缓存策略对请求值进行缓存。

ConnectInterceptor

ConnectInterceptor 在 OKHTTP 底层是通过 SOCKET 的方式于服务端进行连接的,并且在连接建立之后会通过 OKIO 获取通向 server 端的输入流 Source 和输出流 Sink。

CallServerInterceptor

CallServerInterceptor 在 ConnectInterceptor 拦截器的功能就是负责与服务器建立 Socket 连接,并且创建了一个 HttpStream 它包括通向服务器的输入流和输出流。而接下来的 CallServerInterceptor 拦截器的功能使用 HttpStream 与服务器进行数据的读写操作的。

Interceptor 使用

我主要有以下使用场景

  • 增加和修改 header
  • 修改 post 的 body
  • get 请求 变成 post 请求或者反过来
  • 重定向 url
  • …

SelfInteceptor

我们先创建一个抽象类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.shicuiji.Inteceptor;

import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;

import java.io.IOException;

public abstract class SelfInteceptor implements Interceptor {

@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Request.Builder builder = request.newBuilder();
buildSign(request, builder);
Request newRequest = builder.build();
return chain.proceed(newRequest);
}

public abstract void buildSign(Request request, Request.Builder builder);
}

其中,buildSign 是来处理上面的各种情况的。

你可以看到在 intercept 这个函数中,主要参数是

  • chain

从 chain 我们可以得到 request

  • chain.request()
    • 获取 request 的信息
  • request.newBuilder()
    • 从 request 来获取 builder ,然后用来重构 request

最后使用 chain.proceed(newRequest) 来进行新的 request 请求。

Application

我们建立一个 Application 文件,来使用上面的类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import com.shicuiji.Inteceptor.SelfInteceptor;
import okhttp3.*;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;

public class Application {
public static void main(String[] args) {

OkHttpClient okHttpClient = new OkHttpClient.Builder().addInterceptor(new SelfInteceptor() {
@Override
public void buildSign(Request request, Request.Builder builder) {
builder.addHeader("test", "123");
builder.get().url("https://www.bilibili.com/");
}
}).build();
String url = "http://www.baidu.com/";
Request request = new Request.Builder().url(url).delete().build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
System.out.println(e);
}

@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
System.out.println(response);
}
});
}
}

上面可以看出其做了如下的操作

  • 修改 header
  • 重定向网址
  • 修改请求方式「get」

我们在来细分一下相关的使用

增加和修改 header

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import com.shicuiji.Inteceptor.SelfInteceptor;
import okhttp3.*;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;

public class Application {
public static void main(String[] args) {

OkHttpClient okHttpClient = new OkHttpClient.Builder().addInterceptor(new SelfInteceptor() {
@Override
public void buildSign(Request request, Request.Builder builder) {
builder.addHeader("test", "123");
}
}).build();
...
call.enqueue(new Callback() {
...
});
}
}

修改 post 的 body

get 请求 变成 post 请求或者反过来

GET

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import com.shicuiji.Inteceptor.SelfInteceptor;
import okhttp3.*;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;

public class Application {
public static void main(String[] args) {

OkHttpClient okHttpClient = new OkHttpClient.Builder().addInterceptor(new SelfInteceptor() {
@Override
public void buildSign(Request request, Request.Builder builder) {
builder.get();
}
}).build();
...
call.enqueue(new Callback() {
...
});
}
}

POST

重定向 url

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import com.shicuiji.Inteceptor.SelfInteceptor;
import okhttp3.*;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;

public class Application {
public static void main(String[] args) {

OkHttpClient okHttpClient = new OkHttpClient.Builder().addInterceptor(new SelfInteceptor() {
@Override
public void buildSign(Request request, Request.Builder builder) {
builder.url("https://www.bilibili.com/");
}
}).build();
...
call.enqueue(new Callback() {
...
});
}
}
请我喝杯咖啡吧~