Android OKHttp 可能你从来没用过的拦截器 【实用推荐】

//超时
final HttpUrl url = chain.request().url();
throw WeakNetworkManager.get().simulateTimeOut(url.host(), url.port());
case WeakNetworkManager.TYPE_SPEED_LIMIT:
//限速
return WeakNetworkManager.get().simulateSpeedLimit(chain);
default:
//断网
throw WeakNetworkManager.get().simulateOffNetwork(chain.request().url().host());
}
}
}

实现一个OkHttp的Intercepter,根据不同的状态来进行延迟,例如如下的模拟超时

/**

  • 模拟超时
  • @param host
  • @param port
    */
    public SocketTimeoutException simulateTimeOut(String host, int port) {
    SystemClock.sleep(mTimeOutMillis);
    return new SocketTimeoutException(String.format(“failed to connect to %s (port %d) after %dms”, host, port, mTimeOutMillis));
    }

根据Interceptor 可以干很多事情,那么Interceptor到底是什么样的原理呢?

Interceptor原理

先看一下Interceptor的原型

public interface Interceptor {
Response intercept(Chain chain) throws IOException;
}

再看一下OkHttp源码,可以知道,我们的请求最终都会被调用到RealCall中,并执行到如下代码

@Override protected void execute() {
boolean signalledCallback = false;
try {
Response response = getResponseWithInterceptorChain();
}

}

Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List 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));
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(forWebSocket));

Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}

在getResponseWithInterceptorChain 添加了很多OkHttp自定义的拦截器,其中有重定向,Cache,连接请求,发起请求到服务端等。我们来看一下最后几行 代码,RealInterceptorChain是一个Interceptor.Chain类型,并执行chain.proceed,接着看一下proceed方法

//RealInterceptorChain
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {

if (index >= interceptors.size()) throw new AssertionError();
calls++;
// Call the next interceptor in the chain.
RealInterceptorChain next = new RealInterceptorChain(
interceptors, streamAllocation, httpCodec, connection, index + 1, request);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);

return response;
}

重点看一下Call the next interceptor in the chain 下面几行代码,他把当前的interceptor.intercept()时,传入的是下一个interceptor的包装类,RealInterceptorChain 这样就实现了,链式递归调用了,直到最后一个response返回,才会依次返回到第一个interceptor。

可以用如下图大致描述

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

讲了那么多相关的知识点,我们来回到正题,上述推荐小工具的实现步骤介绍

抓包工具实现主要步骤介绍

添加一个抓包入口

在Manifest中注册即可,如下






暴露Interceptor

public final class CaptureInfoInterceptor implements Interceptor{
@Override public Response intercept(Chain chain) throws IOException {
//获取request 所有信息

//获取response 所有信息

//存储抓包数据
CacheUtils.getInstance().saveCapture(request.url().toString(),captureEntity);
}
}

这里其中有两种方式,添加到OkHttp的Interceptor,一种硬编码,如下

new OkHttpClient.Builder()
.addInterceptor(new CaptureInfoInterceptor())
.build();

另一种方式 采用字节码注入的形式,关于字节码注入,可以简单参考我的另一篇Gradle学习笔记,自定义 Transform部分。

存储和读取抓包数据 效率问题

存储时,为了不影响到主APP的网络请求效率,需要在单独的线程中执行IO操作,这里使用了单线程池

public class DiskIOThreadExecutor implements Executor {
private final Executor mDiskIO;
public DiskIOThreadExecutor() {
mDiskIO = Executors.newSingleThreadExecutor();
}
@Override
public void execute(@NonNull Runnable command) {
mDiskIO.execute(command);
}
}

存储

public void saveCapture(final String url, final CaptureEntity value) {
Runnable runnable = new Runnable() {
@Override
public void run() {
String saveUrl = url;
if (url.contains(“?”)) {
saveUrl = saveUrl.substring(0, saveUrl.indexOf(“?”));
}
String key = urlMd5(saveUrl);
sp.edit().putString(key, saveUrl).apply();
checkOrCreateFilePath(key);
File file = new File(captureFilePath + “/” + key + “/” + getCurrentTime() + “.txt”);
BufferedSink bufferedSink = null;
try {
file.createNewFile();
bufferedSink = Okio.buffer(Okio.sink(file));
bufferedSink.writeString(JSON.toJSONString(value), StandardCharsets.UTF_8);
bufferedSink.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (bufferedSink != null) {
try {
bufferedSink.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
};
diskIOThreadExecutor.execute(runnable);
}

读取

读取抓包数据时,不直接读取全部的数据,只读取当前抓包的目录,数据,点击时,在去加载对应的数据

最后

分享一份工作1到5年以上的Android程序员架构进阶学习路线体系,希望能对那些还在从事Android开发却还不知道如何去提升自己的,还处于迷茫的朋友!

  • 阿里P7级Android架构师技术脑图;查漏补缺,体系化深入学习提升

  • **全套体系化高级架构视频;**七大主流技术模块,视频+源码+笔记

有任何问题,欢迎广大网友一起来交流

事Android开发却还不知道如何去提升自己的,还处于迷茫的朋友!**

  • 阿里P7级Android架构师技术脑图;查漏补缺,体系化深入学习提升

    [外链图片转存中…(img-EpxQQao2-1719485411509)]

  • **全套体系化高级架构视频;**七大主流技术模块,视频+源码+笔记

[外链图片转存中…(img-fN4Z4vag-1719485411509)]

有任何问题,欢迎广大网友一起来交流

  • 21
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值