当涉及到Android使用程序中的网络恳求处理时,OkHttp是一个十分强大和盛行的东西。其间一个要害的功用是拦截器(Interceptors),它们答应您在恳求和呼应传输到服务器和使用程序之间履行各种操作。在本文中,我们将深入研究OkHttp拦截器,了解其作业原理以及怎么运用它们来优化您的Android使用程序。

什么是OkHttp拦截器

OkHttp拦截器是一种机制,答应您在网络恳求和呼应的传输过程中履行自界说操作。它们一般用于记载恳求日志、修正恳求头、缓存呼应或进行身份验证等操作。拦截器可以依照增加它们的次序顺次履行,从而形成一个拦截器链。

拦截器链

拦截器链是一个由多个拦截器组成的链条,每个拦截器在恳求和呼应的传输过程中都有时机进行操作。这些拦截器依照它们增加的次序履行,因而次序很重要。以下是一个拦截器链的示意图:

Request 1 -> Interceptor 1 -> Interceptor 2 -> ... -> Interceptor N -> Server
                            <-                <- ... <-                <-
Response 1 <- Interceptor 1 <- Interceptor 2 <- ... <- Interceptor N <- Server

OkHttp中拦截器的作业原理

OkHttp的核心组件是Interceptor接口和RealCall类。Interceptor接口界说了intercept()办法,它接纳一个Chain目标作为参数,该目标用于履行拦截器链上的操作。RealCall类用于实际履行网络恳求并管理拦截器链的履行。

创立OkHttpClient

首要,您需求创立一个OkHttpClient实例,该实例用于建议网络恳求,并配置拦截器链。

OkHttpClient client = new OkHttpClient.Builder()
    .addInterceptor(new CustomInterceptor())
    .build();

建议网络恳求

当您调用client.newCall(request)来创立一个新的网络恳求时,OkHttp会创立一个RealCall目标,该目标代表了实际的网络恳求。接下来,RealCall会履行拦截器链上的操作。

Request request = new Request.Builder()
    .url("https://example.com/api")
    .build();
Call call = client.newCall(request);
Response response = call.execute();

拦截器链履行

拦截器链的履行是在RealCall类中完成的,它遍历拦截器列表并依照增加次序顺次履行。以下是相关源码示例:

public Response getResponseWithInterceptorChain() throws IOException {
    // 创立一个初始的Interceptor.Chain
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());
    interceptors.add(retryAndFollowUpInterceptor);
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    interceptors.add(new CacheInterceptor(client.internalCache()));
    interceptors.add(new ConnectInterceptor(client));
    interceptors.add(new CallServerInterceptor(false));
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, 0, originalRequest, this, callStackTrace);
    // 顺次履行拦截器
    return chain.proceed(originalRequest);
}

Interceptor.Chain的实现

RealInterceptorChain类实现了Interceptor.Chain接口,它包含了当时恳求的信息,并负责履行拦截器链上的操作。在proceed()办法中,它顺次调用拦截器的intercept()办法,将恳求传递给下一个拦截器,并最终回来呼应。

public Response proceed(Request request) throws IOException {
    // 履行下一个拦截器或许建议网络恳求
    if (index >= interceptors.size()) throw new AssertionError();
    calls++;
    if (chain == null) throw new IllegalStateException("Check failed.");
    if (eventListener != null) {
        eventListener.callStart(this);
    }
    // 获取当时拦截器
    Interceptor interceptor = interceptors.get(index++);
    // 调用拦截器的intercept办法,将恳求传递给下一个拦截器或许履行网络恳求
    Response response = interceptor.intercept(this);
    if (eventListener != null) {
        eventListener.callEnd(this);
    }
    return response;
}

编写自界说拦截器

要编写自界说拦截器,首要需求实现Interceptor接口,并实现intercept()办法。这个办法接纳一个Chain目标作为参数,答应您访问和操作恳求和呼应。

public class CustomInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        // 在恳求前履行的代码
        Request originalRequest = chain.request();
        // 可以修正恳求
        Request modifiedRequest = originalRequest.newBuilder()
                .addHeader("Authorization", "Bearer YourAccessToken")
                .build();
        // 履行恳求
        Response response = chain.proceed(modifiedRequest);
        // 在呼应后履行的代码
        // 可以修正呼应
        return response;
    }
}

实际使用示例

以下是一些实际运用示例,展现了怎么运用OkHttp拦截器来实现不同的功用

日志记载

这个拦截器用于记载恳求和呼应的详细信息,有助于调试和排查问题。

public class LoggingInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        long startTime = System.nanoTime();
        Log.d("OkHttp", String.format("Sending request %s on %s%n%s",
            request.url(), chain.connection(), request.headers()));
        Response response = chain.proceed(request);
        long endTime = System.nanoTime();
        Log.d("OkHttp", String.format("Received response for %s in %.1fms%n%s",
            response.request().url(), (endTime - startTime) / 1e6d, response.headers()));
        return response;
    }
}

身份验证

这个拦截器用于在每个恳求中增加身份验证标头,以保证恳求是经过身份验证的。

public class AuthInterceptor implements Interceptor {
    private final String authToken;
    public AuthInterceptor(String authToken) {
        this.authToken = authToken;
    }
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request originalRequest = chain.request();
        // 增加身份验证标头
        Request authenticatedRequest = originalRequest.newBuilder()
                .header("Authorization", "Bearer " + authToken)
                .build();
        return chain.proceed(authenticatedRequest);
    }
}

缓存

这个拦截器用于实现呼应缓存,以削减对服务器的恳求。

public class CacheInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        // 在这里查看是否有缓存可用,假如有,回来缓存的呼应
        Response response = chain.proceed(request);
        // 在这里将呼应缓存起来
        return response;
    }
}

恳求重试

这个拦截器用于处理恳求失利时的重试逻辑。

public class RetryInterceptor implements Interceptor {
    private final int maxRetryCount;
    public RetryInterceptor(int maxRetryCount) {
        this.maxRetryCount = maxRetryCount;
    }
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        Response response = null;
        IOException lastException = null;
        for (int retryCount = 0; retryCount < maxRetryCount; retryCount++) {
            try {
                response = chain.proceed(request);
                if (response.isSuccessful()) {
                    return response;
                }
            } catch (IOException e) {
                lastException = e;
            }
        }
        // 假如到达最大重试次数依然失利,抛出异常
        throw lastException;
    }
}

自界说呼应处理

这个拦截器用于在接纳到呼应后履行自界说的呼应处理逻辑。

public class ResponseProcessingInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        Response response = chain.proceed(request);
        // 在这里对呼应进行自界说处理
        return response;
    }
}

过错处理

这个拦截器用于处理一些常见的过错状况

public class ErrorHandlingInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        try {
            Response response = chain.proceed(request);
            // 查看呼应是否成功
            if (!response.isSuccessful()) {
                // 在这里处理过错,可以抛出自界说异常
                throw new MyHttpException(response.code(), response.message());
            }
            return response;
        } catch (IOException e) {
            // 在这里处理网络连接过错
            throw new MyNetworkException(e.getMessage(), e);
        }
    }
}

重定向恳求

这个拦截器用于自界说重定向行为

public class RedirectInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        Response response = chain.proceed(request);
        // 查看是否是重定向呼应
        if (response.isRedirect()) {
            String newUrl = response.header("Location");
            if (newUrl != null) {
                // 构建新的恳求并持续
                Request newRequest = request.newBuilder()
                        .url(newUrl)
                        .build();
                response = chain.proceed(newRequest);
            }
        }
        return response;
    }
}

结论

OkHttp拦截器是Android使用程序中处理网络恳求的有力东西。通过创立自界说拦截器,您可以在恳求和呼应的传输过程中履行各种操作,以优化您的使用程序。无论是日志记载、身份验证、缓存还是其他操作,拦截器都可以协助您更好地操控和定制网络恳求流程。

推荐

android_startup: 提供一种在使用发动时可以愈加简单、高效的方式来初始化组件,优化发动速度。不仅支撑Jetpack App Startup的全部功用,还提供额外的同步与异步等候、线程操控与多进程支撑等功用。

AwesomeGithub: 根据Github的客户端,纯练习项目,支撑组件化开发,支撑账户密码与认证登陆。运用Kotlin言语进行开发,项目架构是根据JetPack&DataBinding的MVVM;项目中运用了Arouter、Retrofit、Coroutine、Glide、Dagger与Hilt等盛行开源技术。

flutter_github: 根据Flutter的跨渠道版别Github客户端,与AwesomeGithub相对应。

android-api-analysis: 结合详细的Demo来全面解析Android相关的知识点, 协助读者可以更快的掌握与理解所阐述的要点。

daily_algorithm: 每日一算法,由浅入深,欢迎加入一起共勉。