HTTP/REST是目前最主流的前后端接口设计,在测试、线上环境里截获HTTP请求可以有效诊断接口请求错误、响应性能、网络环境对页面响应的影响、用户路径分析等。本文从截获APP HTTP请求开始讲起,介绍如何分析错误的HTTP响应,以及分析响应的性能,穿插实战中找到的问题案例。系列文章将一步步介绍精细化分析。
APP端和服务器端的交互是非常重要的一个环节,能够获取交互信息可以有效提高测试分析的效率,找到服务端的问题、定位APP代码问题,甚至用来分析用户路径、流量等,是提高产品质量的重要工具。
说到HTTP抓包,第一个想到的肯定是代理软件,例如Charles和Fiddler,搜一下,教程很多,用过之后缺点非常多:
理想的情况应该是在APP内部有一个机制截获APP的HTTP请求响应,log下来,然后能够方便获取做进一步分析。这样一来APP自然就会log自己的流量;同时因为是APP内部,所以https不再是问题;数据可以灵活获取、分析;而且可以根据不同配置(测试环境、用户环境)采取不同的log策略,用来不同的分析(测试时全log,分析错误、性能、稳定性等;用户环境打点、报告问题请求响应)。
然而只有有些HTTP库,比如okhttp,提供了比较方便的log接口(Interceptor),很多http请求都没有这样的log接口。另外APP自己会用很多三方库里也会发出请求,三方库代码不好改。最后,监控点如果需要人工维护,成本也很高。
Appetizer 通过插桩技术解决这以上所有问题,插桩是对APK的字节码(Dex文件)进行修改,根据规则截获APP以及三方库内发送的HTTP请求,并log HTTP请求和响应,相比系统代理,插桩截获有以下优势:
APP中常用的HTTP请求库有HttpURLConnection(HUC), Apache HTTP Client, OkHttp, Retrofit, Volley,还有一些“快速开发框架”(实际内部封装了这些库)。HUC是java.net.HttpURLConnection
提供的功能,是Java自带的标准库,通常是第三方库用来请求HTTP的(这样就可以只依赖标准库)。Apache是曾经Android推荐的HTTP库,从5.0开始已经不再推荐,不过有一些老的三方库、控件库依然使用着Apache。OkHttp 是Square公司开发的方便好用的现代的HTTP请求库,目前使用非常流行,Retrofit也是依赖于OkHttp,OkHttp有2.x (包名com.squareup.okhttp
), 3.x(包名okhttp3.*
)两个版本,从5.0+开始,标准库的HUC实际内部实现是okhttp。最后Volley是Google官方出的一套小而巧的异步请求库,
其实是个框架,底层可以对接其他HTTP库,官方提供了Apache和HttpURLConnection的支持。此外国内外有很多“所谓的HTTP库”其实都是对这几个库的封装。
下图总结了一下常见的库的依赖关系,还有一些比较上层的封装库和开发框架:
Appetizer本身通过字节码插桩的方式来截获APP调用HTTP库的API。Appetizer截获最底层的HUC, Apache和okhttp 2.x和3.x,从而支持所有依赖于这几个底层库的框架,如果有我们没有提到的HTTP库,请在评论区告知。
对于okhttp 截获比较简单,因为okhttp提供了天然的Interceptor接口,Appetizer如果探测到APP使用了okhttp,则在程序开头注册一个自己的interceptor。而Apache HTTP Client和HUC就没有这么方便的机制,于是Appetizer会扫描整个APP的代码,为每处调用加上log代码,例如:
URLConnection conn = new URL("https://appetizer.io").openConnection();
// Appetizer搜索到openConnection 的调用,在这里插入log代码,记录conn的内容(请求头、响应内容等)
conn.getResponseCode();
插桩技术相比较于需要接入SDK的方式(比如Facebook Stetho和一些监控库)有以下优点:
有了截获的HTTP数据后,我们可以开始分析,精细化HTTP分析对于开发、测试以至于产品分析都有非常重要的用处。我们会分几期介绍基于HTTP数据的各种分析。
最常见的是对错误返回码系列的分析,4xx是client端的问题,5xx是server端的问题。
对于4xx的返回码(如下图),Appetizer会给出完整的请求URL(包括请求参数),以及请求Header(见折叠),通常这类情况是由于构造的的URL有问题,例如参数问题,或者是一些字符串转码方面的问题。Appetizer 1.2.0推出后,报告页面右上角会多一个按钮,用于导出这个问题请求的cURL 命令行,可以轻松导入postman进行进一步测试
如果返回码是5xx,那就是后端同学的锅了,同样,可以产生了cURL命令行发给后端同学去反复测试这个接口。
如何接入Appetizer插桩服务?
使用我们的图形化界面客户端,参考:https://testerhome.com/topics/8162
使用Python客户端(考虑使用脚本插桩或者接入Jenkins): https://github.com/appetizerio/insights.py
除了GET,POST,其他HTTP 方法,比如PUT支持吗?
我们支持HTTP协议支持的所有HTTP方法,包括更为小众的PATCH (例如zhihu用了),HEAD等。所以只要是REST API都可以用Appetizer来截获分析。
APP可以加固么?
不可以,加固后的APP不能修改,开发包可以考虑只混淆
APP可以混淆么?
插桩本身支持混淆后的APP,但是有些截获功能是通过寻找目标库的API实现的,混淆后有些库的API被去除或者改名会导致部分库无法识别,无法截获。目前如果使用了okhttp,最好保证库不会被混淆,可以在proguard规则中增加:
-keepattributes Signature
-keepattributes Annotation
-keep class okhttp3.** { *; }
-keep interface okhttp3.** { *; }
-dontwarn okhttp3.**
-dontwarn okio.**
ReactNative/Weex等H5技术开发的APP支持么?
经测试是完全支持的。ReactNative的HTTP库用的是OkHttp,在我们支持范围内。
Kotlin 开发的APP支持么?
经测试是完全支持的。
webview控件里的页面请求能截获吗?
正在开发中
插桩截获功能对性能的影响怎样?
插桩代码的运行代价是记录HTTP请求,Appetizer只记录请求响应的header内容,并不记录body,从而性能影响很小,记录单个请求耗时最多1ms。同时,因为HTTP请求都是在APP的子线程上完成的,所以不会造成任何主线程卡顿
使用了一些会发出HTTP请求的C++库(.so)能截获吗?
目前不支持,插桩仅限Java代码。例如使用了Lua 解释器、C++的视频/音频播放器目前都暂不支持,如果希望支持,请在评论区留言
支持手游吗?
同上。手游的HTTP是从C++库里发出的
支持非HTTP协议,例如RTP之类的
暂不支持
iOS呢?
参考光哥的文