写点什么

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

发布于: 2021 年 11 月 08 日
  • 抓包数据以时间为纬度,默认存储到手机缓存下 /Android/Data/包名/Cache/capture/ 下

  • 支持 Http/Https 协议的抓包,分类请求方式/请求 URL/请求 Header/请求体/响应状态/响应 Header/响应体

  • 支持一键复制对应的状态

  • 响应体如果是 JSON,支持自动格式化

  • 抓包数据,默认缓存一天

Github 地址

代码已经托管到 Github 地址:github.com/DingProg/Ne…

快速接入


[



](https://jitpack.io/#DingProg/NetworkCaptureSelf)


allprojects {repositories {maven { url 'https://jitpack.io' }}}


dependencies {debugImplementation 'com.github.DingProg.NetworkCaptureSelf:library:v1.0.1'releaseImplementation 'com.github.DingProg.NetworkCaptureSelf:library_no_op:v1.0.1' }


在你的全局 OkHttp 中添加 Interceptor


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

原理及涉及知识详解

作为 Android 开发,说到 OKHttp 的 Interceptor,肯定熟悉不过了。那么你对 Interceptor 又了解多少呢?你都使用过那些 OKHttp 的 Interceptor 呢?


我们先来看一下最近滴滴很火的哆啦 A 梦

DoraemonKit

长下面这个样子



其中关于网络模块 OK Http 的监听如下


OkHttpClient client = new OkHttpClient().newBuilder()//用于模拟弱网的拦截器.addNetworkInterceptor(new DoraemonWeakNetworkInterceptor())//网络请求监控的拦截器 ,用于网络流量监听等.addInterceptor(new DoraemonInterceptor()).build();


这里举例说一下弱网模拟

弱网模拟

看一下他的实现代码


public class DoraemonWeakNetworkInterceptor implements Interceptor {


@Overridepublic Response intercept(Chain chain) throws IOException {if (!WeakNetworkManager.get().isActive()) {Request request = chain.request();return chain.proceed(request);}final int type = WeakNetworkManager.get().getType();switch (type) {case WeakNetworkManager.TYPE_TIMEOUT://超时 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<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));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 方法


//RealInterceptorChainpublic Response proceed(


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


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 中注册即可,如下


<activityandroid:name="com.ding.library.internal.ui.CaptureInfoActivity"android:configChanges="keyboardHidden|orientation|screenSize|smallestScreenSize|locale"android:launchMode="singleInstance"android:screenOrientation="portrait"android:theme="@style/AppTheme.NoActionBar" />


<activity-aliasandroid:label="抓包入口"android:name="CaptureInfoActivity"android:targetActivity="com.ding.library.internal.ui.CaptureInfoActivity"><intent-filter><action android:name="android.intent.action.MAIN"/><category android:name="android.intent.category.LAUNCHER"/></intent-filter></activity-alias>

暴露 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() {

评论

发布
暂无评论
Android OKHttp 可能你从来没用过的拦截器 【实用推荐】