在 Android 中使用 OkHttp 的自定义 Interceptor 实现统一请求头添加是一种高效的方式,可以避免在每个请求中重复设置头部。以下是详细实现步骤:
1. 创建自定义拦截器类
java
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;
public class HeaderInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
// 1. 获取原始请求
Request originalRequest = chain.request();
// 2. 添加统一请求头(可扩展更多)
Request newRequest = originalRequest.newBuilder()
.header("User-Agent", "MyApp/Android/1.0.0")
.header("Accept-Language", "zh-CN")
.header("Authorization", getAuthToken()) // 示例:动态token
.header("Custom-Header", "Value")
// 添加更多统一头部...
.build();
// 3. 继续执行请求
return chain.proceed(newRequest);
}
// 示例方法:获取动态认证token(根据实际情况实现)
private String getAuthToken() {
// 这里可以是获取本地存储的token
return "Bearer your_token_here";
}
}
2. 在 OkHttpClient 中注册拦截器
java
// 创建 OkHttpClient 实例
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new HeaderInterceptor()) // 添加统一头部拦截器
// 可选:添加其他拦截器(如日志拦截器)
.addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
.build();
3. 使用 OkHttpClient 发送请求(示例)
java
// 创建请求(无需单独设置统一头部)
Request request = new Request.Builder()
.url("https://api.example.com/data")
.build();
// 异步执行
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
// 处理失败
}
@Override
public void onResponse(Call call, Response response) throws IOException {
// 处理响应
}
});
关键点说明
-
拦截器类型选择:
addInterceptor
:应用拦截器,处理非重定向请求addNetworkInterceptor
:网络拦截器,处理实际网络请求(包含重定向)
-
动态头部处理:
java// 示例:根据请求URL动态添加头部 if (originalRequest.url().toString().contains("/api/secure")) { newRequestBuilder.header("Security-Key", "special_key"); }
-
覆盖优先级:
-
拦截器添加的头部 会覆盖 请求中设置的相同名称头部
-
若需保留请求特定头部,使用以下方式:
javaif (!originalRequest.headers().contains("Special-Header")) { newRequestBuilder.header("Special-Header", "default"); }
-
高级场景处理
1. 需要动态 token 的场景
java
.header("Authorization", getCurrentToken()) // 实现动态获取
// 实现示例
private String getCurrentToken() {
return App.getAuthManager().getAccessToken();
}
2. 条件性添加头部
java
Request.Builder builder = originalRequest.newBuilder();
if (isUserLoggedIn()) {
builder.header("User-ID", getUserId());
}
3. 多模块差异化处理
java
String path = originalRequest.url().encodedPath();
if (path.startsWith("/api/v1")) {
builder.header("API-Version", "v1");
} else if (path.startsWith("/api/v2")) {
builder.header("API-Version", "v2");
}
完整流程图
graph TD
A[发起请求] --> B[拦截器处理]
B --> C{是否添加统一头部?}
C -->|是| D[添加预设头部]
C -->|否| E[保留原始头部]
D --> F[执行网络请求]
E --> F
F --> G[返回响应]
通过这种方式,您可以:
- 集中管理所有公共请求头
- 动态处理认证信息
- 根据不同请求条件添加不同头部
- 减少代码重复和维护成本
提示:对于敏感信息(如认证 token),建议结合 Android 的安全存储机制(如 EncryptedSharedPreferences)进行存储和获取。