三方庫源碼筆記(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

相關文章
相關標籤/搜索