前言

在平时开发中,你有没有下面这样的困扰呢?

场景一

明明是服务端的接口数据错误,而QA(测试)第一个找到的可能是客户端开发的你,为什么这个页面出现错误了?

而作为客户端开发的你,可能要拿出测试机连上电脑,打一下Log,看一下到底返回了什么数据,导致页面错误。

或者高级一点的QA,会自己打Log或者连接抓包工具看一下服务端返回的具体数据,然后把Bug提给对应的人,而大多数公司的业务测试,都仅仅是测试业务,不管技术层的。我司的大部分QA,属于外派来的,一般也只测试业务,每次有问题,都先找客户端。

场景二

你现在正在外面做地铁,产品或者你领导突然给你反馈,你之前做的那块业务,突然线上跑不起来了,不行了。你一想,这肯定是服务端的问题啊,但是怎么证明呢?

场景三

服务端上个线,每次都需要客户端加班配合,说有问题,可以及时帮助排查问题。

推荐一个小工具

说了这么多,就是缺少一个端上的抓包小工具,来查看服务端的数据是否有问题,今天推荐的是一个基于OKHttp的抓包工具。 部分截图如下


支持功能

  • 自带分类接口
  • 抓包数据以时间为纬度,默认存储到手机缓存下 /Android/Data/包名/Cache/capture/ 下
  • 支持Http/Https协议的抓包,分类请求方式/请求URL/请求Header/请求体/响应状态/响应Header/响应体
  • 支持一键复制对应的状态
  • 响应体如果是JSON,支持自动格式化
  • 抓包数据,默认缓存一天

Github地址

代码已经托管到Github 地址:https://github.com/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(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() {mDiskIO = Executors.newSingleThreadExecutor();}@Overridepublic void execute(@NonNull Runnable command) {mDiskIO.execute(command);}
}

存储

   public void saveCapture(final String url, final CaptureEntity value) {Runnable runnable = new Runnable() {@Overridepublic 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);}

读取

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

public List<String> getCapture() {File file = new File(captureFilePath);return getFileList(file);
}public List<String> getCapture(String key) {File file = new File(captureFilePath + "/" + key);return getFileList(file);
}

好了,关于这个小工具,就介绍那么多了,具体细节代码,可以直接查看Github代码仓库,https://github.com/DingProg/NetworkCaptureSelf

总结

其实关于抓包工具,有一些成熟的方案。

  • 电脑端的有Fiddler、Charels,Wireshark等,但是不是特别方便。
  • APP可以抓其他包的工具,如NetWorkPacketCapture/抓包精灵/AndroidHttpCapture,但是都一些限制条件,要么代码没开源,广告多。要么就是只能在WIFI下,或者要么就是需要Root等,不太好定制。

本文,主要是介绍OkHttp的拦截器,并从中发现可以干很多事情。如文中有错误,还忘指正,感谢。

最后也感谢你的点赞及Github的Star NetworkCaptureSelf

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

  1. 【Android】OkHttp源码解读逐字稿(1)-拦截器

    目录 0.前言 1.OkHttp的简单使用 2.浅析开始 拦截器 链式调用流程示意图 第 0 个拦截器 第一个 拦截器 RetryAndFollowUpInterceptor 第二个拦截器 Bridg ...

  2. OKHttp 可能你从来没用过这样的拦截器

    码个蛋(codeegg) 第 835 次推文 作者:北斗星_And 博客:https://juejin.im/post/5ddddd2a6fb9a07161483fb2 码妞看世界 世界比树枝错综复杂 ...

  3. Android—OkHttp同步异步请求过程源码分析与拦截器

    OkHttp同步请求步骤: 创建OkHttpClient,客户对象 创建Request,请求主体,在请求主体设置请求的url,超时时间等 用newCall(request)将Reuqest对象封装成C ...

  4. android 方法拦截器,Android的OkHttp包中的HTTP拦截器Interceptor用法示例

    OkHttp(GitHub:https://github.com/square/okhttp) 的 Interceptor 就如同名称「拦截器」一样,拦截你的 Request 做一些你想做的事情再送出 ...

  5. Android OkHttp 源码解析 - 拦截器

    一.前言 看一下 RealCall 中的拦截器排序: Response getResponseWithInterceptorChain() throws IOException {// Build a ...

  6. Android OkHttp(1)

     Android OkHttp(1) OkHttp是一个流行的第三方开源网络请求框架,在目前的一些APP开发中比较流行.Android平台开源的网络请求框架不少,比如常见的Volley, Asyn ...

  7. Android OkHttp框架解析

    Okhttp是由Sqare公司开发的开源网络访问库,是目前比较火的网络框架, 它处理了很多网络疑难杂症:会从很多常用的连接问题中自动恢复.如果你的服务器配置了多个IP地址,当第一个IP连接失败的时候, ...

  8. Android okHttp上传图片

    今天,简单讲讲Android 使用OK HTTP上传图片. 不废话了,直接上代码: /*** 上传图片* @param url* @param imagePath 图片路径* @return 新图片的 ...

  9. android okhttp使用cookie请求

    今天,简单讲讲Android的http使用cookie请求. 现在,做一个功能,出现一个奇怪现象,就是老是登陆成功后,发送请求获取消息,老是提示我没有登陆.我自己都不知道是什么原因,这个也是我对网络通 ...

最新文章

  1. JPA 注解的CascadeType属性
  2. Tableau实战系列浏览 Tableau 环境(八) -tableau文件类型、语言和区域设置以及图标
  3. 【干货】精通网红OSPF协议---进阶篇
  4. s6730堆叠_不再只是堆叠硬件 ivvi S6全方位评测
  5. (转)JDK 1.5中的ENUM用法
  6. ArrayList 实现原理及源码解析(jdk8 底层⽤的是数组)
  7. python没基础能自学吗-python自学没有基础会不会不好学?
  8. MACH SYSTEMS—总线接口转换工具
  9. 网易云课堂C++开发工程师案例-网吧收银系统(MFC+ADO) C++收银系统
  10. 中文ssid linux,分享|LinSSID:一款Linux下的图形化Wi-Fi扫描器
  11. while循环实例C语言,实例之while循环
  12. RouterOS之DDNS(动态域名)
  13. Convex Optimization: 3 Convex functions
  14. 两台笔记本相连是不是计算机网络,打扰一下,如何将两台笔记本电脑的屏幕连接在一起?...
  15. chromecast网络访问受限
  16. Facebook一季报解读:未来十年要打造一个怎样的世界?
  17. jmeter参数化设置
  18. 广丰计算机技术学院,广丰区五都镇中学祝晓旺——信息技术教育的拓荒者
  19. 小巧高效的php框架,猿团YTFramework框架上线 让PHP开发更简单高效
  20. STM32F103C8T6核心板控制器下,通过电路搭建实现LED灯轮流闪烁的实验操作

热门文章

  1. python录入数据至ppt_利用Python进行数据分析之 数据加载.ppt
  2. 20041220 GETSTRING.CS
  3. java和以太坊交互_Android怎么和以太坊智能合约交互
  4. 面试中 项目遇见的难点答案_你和offer之间只差这几个面试问题!常见面试问题汇总...
  5. Linux常用命令及面试题
  6. 学习工行MySQL研发管控和治理实践的过程
  7. Ogitor中Gizmo的绘制技巧
  8. ur机械臂 控制器_UR机器人远程控制研究
  9. MetaMask钱包登录Ganache-cli内的账户,出现无法获取链 IC,您的 RPC URL 地址是正确的么?问题
  10. cgb2110-day02