在 OkHttp 中使用 Interceptor 预处理网络请求

通过定义拦截器 Interceptor ,可以在发送请求或接受请求响应时对数据进行预处理和判断。在开发阶段,为了调试方便,通常在请求的时候,可以直接通过 Log 打印出请求的一些信息,而对于 HeaderToken 的统一管理添加,也可以通过 Interceptor 来实现。

HelloWorld

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
import okhttp3.*;
import java.io.IOException;
public class MyInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
// 封装 headers,添加请求头信息
Request request = chain.request().newBuilder()
.addHeader("Content-Type", "application/json") //添加请求头信息
.build();
Headers headers = request.headers();
System.out.println("Content-Type is : " + headers.get("Content-Type"));
String requestUrl = request.url().toString(); // 获取请求url地址
String methodStr = request.method(); // 获取请求方式
RequestBody body = request.body(); // 获取请求body
String bodyStr = (body==null?"":body.toString());
Response response = chain.proceed(request);
if (response != null) {
System.out.println("Response is not null");
} else {
System.out.println("Response is null");
}
return response;
}
}

上面的代码定义了一个 Interceptor ,对 request 请求添加了一个请求头 Content-Type ,值是 application/json,使用了该 Interceptorclient 发起的所有请求,都会自动添加上这个请求头。

request 的几个重要方法:

  • url : 获取请求地址
  • method : 获取请求方式
  • body : 获取请求体

使用 Interceptor

1
2
3
OkHttpClient client = new OkHttpClient().newBuilder()
.addInterceptor(new MyInterceptor())
.build();

TokenInterceptor

拦截器的作用在于处理请求信息,对请求数据加密或者在请求响应时存储 cookies ,或者封装 access token 便于服务器验证等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Interceptor mTokenInterceptor = new Interceptor() {
@Override public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
// sToken == null : un-logined
// hasAuthorizationHeader : 已经有 Authorization 信息
if (Your.sToken == null || hasAuthorizationHeader(originalRequest)) {
return chain.proceed(originalRequest);
}
// 添加 Authorization
Request authorised = originalRequest.newBuilder()
.header("Authorization", Your.sToken)
.build();
return chain.proceed(authorised);
}
};

如果 token 是空的,比如对于登录请求,是没有 token 的,只有等到登陆之后才有 token,这时候就不需要添加 token。另外,如果请求中已经带有验证 header 了,比如你手动设置了一个另外的 token,那么也不需要再为请求添加这一个 token

Authenticator

如果需要在遇到 401 Not Authorised 的时候进行刷新 token,可以使用 Authenticator,这是一个专门设计用于当验证出现错误的时候,进行询问获取处理的拦截器:

1
2
3
4
5
6
7
8
9
Authenticator mAuthenticator = new Authenticator() {
@Override public Request authenticate(Route route, Response response)
throws IOException {
String sToken = service.refreshToken();
return response.request().newBuilder()
.addHeader("Authorization", sToken)
.build();
}
}

分别使用 OkHttpClient.Builder 对象的 addNetworkInterceptor(…)authenticator(…) 添加定义好的拦截器。

Cookies

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class CookiesInterceptor implements Interceptor {
private Context context;
public CookiesInterceptor(Context context) {
this.context = context;
}
// 重写拦截方法,处理自定义的Cookies信息
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Request compressedRequest = request.newBuilder()
.header("cookie", getCookies(context))
.build();
Response response = chain.proceed(compressedRequest);
// 保存 cookie
saveCookies(response.headers(), context);
return response;
}
}

上面定义的 CookiesInterceptor 当请求成功之后,使用 saveCookies 方法保存服务器返回的 cookies 信息,在请求之前,读取本地缓存好的 cookie 信息添加到 header 中。

配置 HttpClient

1
2
3
4
5
6
7
8
9
OkHttpClient client = ...;
// 设置拦截器,以用于自定义Cookies的设置
client.networkInterceptors()
.add(new CookiesInterceptor(context));
// 设置缓存目录
File cacheDirectory = new File(context.getCacheDir()
.getAbsolutePath(), "HttpCache");
Cache cache = new Cache(cacheDirectory, 20 * 1024 * 1024);
client.setCache(cache);