三方库源码笔记(12)-OkHttp / Retrofit 开发调试利器

对于 Android Developer 来讲,不少开源库都是属于开发必备的知识点,从使用方式到实现原理再到源码解析,这些都须要咱们有必定程度的了解和运用能力。因此我打算来写一系列关于开源库源码解析实战演练的文章,初定的目标是 EventBus、ARouter、LeakCanary、Retrofit、Glide、OkHttp、Coil 等七个知名开源库,但愿对你有所帮助 😇😇java

公众号:字节数组git

系列文章导航:github

在使用 OkHttp 或者 Retrofit 的时候,我以为大部分开发者会作得最多的自定义实现就是拦截器了。由于 OkHttp 的拦截器真的是太有用了,咱们的不少需求:添加 Header、计算并添加签名信息、网络请求记录等均可以经过拦截器来自动完成,只要定义好规则,就能够覆盖到全局的 OkHttp 网络请求数据库

按照我写 [三方库源码笔记] 这系列文章的习惯,我是每写一篇关于源码讲解的文章,就会接着写一篇关于该三方库的自定义实现或者是扩展阅读。因此,承接上一篇文章:三方库源码笔记(11)-OkHttp 源码详解 本篇文章就来写关于 OkHttp 的实战内容,来实现一个在移动端的可视化抓包工具:Monitor数组

1、Monitor

Monitor 适用于使用了 OkHttp/Retrofit 做为网络请求框架的项目,只要添加了 MonitorInterceptor 拦截器,Monitor 就会自动记录并保存全部的网络请求信息且自动弹窗展现markdown

最后实现的效果以下所示:网络

2、实现思路

这里来简单地介绍下 Monitor 的实现思路app

其实 Monitor 是我蛮久前写的一个开源库了,恰好和我如今要写的文章主题相符,就趁着这机会作了一次总体重构,彻底使用 Kotlin 语言来实现,请放心食用。其核心思路就是经过 Interceptor 拿到 Request 和 Response,记录各项请求信息,存到数据库中进行持久化保存,在实现思路上相似于 squareup 官方的ogging-interceptor,只是说 Monitor 会更加直接和方便😋😋框架

debug 版本的 MonitorInterceptor 的大致框架以下所示。HttpInformation 是对 request 和 response 的一个实体封装,也是最终会存到数据库中的实体类。经过 chain 拿到 request,先对本地数据库进行预先占位,在 proceed 后拿到 response,对本次请求结果进行解析,全部信息都存到 HttpInformation 中再来更新数据库,同时弹出 Notificationmaven

/** * 做者:leavesC * 时间:2020/10/20 18:26 * 描述: * GitHub:https://github.com/leavesC */
class MonitorInterceptor(context: Context) : Interceptor {

    @Throws(IOException::class)
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        val httpInformation = HttpInformation()
        processRequest(request, httpInformation)
        httpInformation.id = insert(httpInformation)
        val response: Response
        try {
            response = chain.proceed(request)
        } catch (e: Throwable) {
            httpInformation.error = e.toString()
            throw e
        } finally {
            update(httpInformation)
        }
        processResponse(response, httpInformation)
        update(httpInformation)
        return response
    }

    private fun processRequest(request: Request, httpInformation: HttpInformation) {
        ···
    }

    private fun processResponse(response: Response, httpInformation: HttpInformation) {
        ···
    }

    private fun showNotification(httpInformation: HttpInformation) {
        ···
    }

}
复制代码

release 版本的 MonitorInterceptor 则不会作任何操做,只是单纯将请求转发出去而已,不会形成多余的性能消耗和引用

class MonitorInterceptor(context: Context) : Interceptor {

    @Throws(IOException::class)
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        return chain.proceed(request)
    }

}
复制代码

HttpInformation 包含了单次网络请求下全部关于 request 和 response 的请求参数和返回值信息,responseBody 只会保存文本类型的返回值(例如 Json 和 XML),图片这类二进制文件则不会进行保存

class HttpInformation {
    
    var url = ""
    var host = ""
    var path = ""
    var scheme = ""
    var protocol = ""
    var method = ""

    var requestHeaders = mutableListOf<HttpHeader>()
    var responseHeaders = mutableListOf<HttpHeader>()

    var requestBody = ""
    var requestContentType = ""
    var requestContentLength = 0L

    var responseBody = ""
    var responseContentType = ""
    var responseContentLength = 0L

    var requestDate = 0L
    var responseDate = 0L

    var responseTlsVersion = ""
    var responseCipherSuite = ""

    var responseCode = DEFAULT_RESPONSE_CODE
    var responseMessage = ""

    var error: String? = null
    
}
复制代码

HttpInformation 则是用 Room 数据库来持久化保存,不得不说的是,Jetpack 中的 Room 和 LiveData 来搭配使用仍是很爽的,将 LiveData 做为数据库的返回值,能够很方便地以观察者模式来实时监听数据库中的数据变化

/** * @Author: leavesC * @Date: 2020/11/14 16:14 * @Desc: */
@Dao
interface MonitorHttpInformationDao {

    @Query("SELECT * FROM monitor_httpInformation WHERE id =:id")
    fun queryRecordObservable(id: Long): LiveData<HttpInformation>

    @Query("SELECT * FROM monitor_httpInformation order by id desc limit :limit")
    fun queryAllRecordObservable(limit: Int): LiveData<List<HttpInformation>>

    @Query("SELECT * FROM monitor_httpInformation order by id desc")
    fun queryAllRecordObservable(): LiveData<List<HttpInformation>>
    
}
复制代码

UI 层则不用本身去考虑线程切换和内存泄露这类问题,直接进行 observe 便可

private val monitorViewModel by lazy {
        ViewModelProvider(this).get(MonitorViewModel::class.java).apply {
            allRecordLiveData.observe(this@MonitorActivity, Observer {
                monitorAdapter.setData(it)
            })
        }
    }
复制代码

3、远程引用

代码我已经发布到了 jitpack,方便你们直接远程依赖使用。同时引入 debug 和 release 版本的依赖,release 版本的 MonitorInterceptor 不会作任何操做,避免了信息泄露,也不会增长 Apk 体积大小

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

        dependencies {
           debugImplementation 'com.github.leavesC.Monitor:monitor:1.1.3'
           releaseImplementation 'com.github.leavesC.Monitor:monitor-no-op:1.1.3'
        }
复制代码

只要向 OkHttpClient 添加了 MonitorInterceptor,以后的操做就都会自动完成

val okHttpClient = OkHttpClient.Builder()
            .addInterceptor(MonitorInterceptor(Context))
            .build()
复制代码

4、Github

GitHub 连接点击这里:Monitor

相关文章
相关标签/搜索