使用okhttp監(jiān)控網(wǎng)絡數(shù)據(jù)

這里使用Okhttp寫了一個demo來監(jiān)聽網(wǎng)絡請求過程中的一系列數(shù)據(jù),包括當前網(wǎng)絡類型、請求體、響應體大小,url,請求方式,當然還有本次核心獲取域名解析時長,建立連接時長,保持連接時長,請求總時長這些數(shù)據(jù)。

一次網(wǎng)絡請求經(jīng)歷了哪些過程

通過域名訪問的方式來請求網(wǎng)絡時,會經(jīng)歷下列過程:
1.DNS解析:通過域名服務器或者本地host將域名解析成ip地址
2.建立連接:三次握手
3.發(fā)送數(shù)據(jù):通過GET/POST/PUT等方式將數(shù)據(jù)(header和body)發(fā)送給服務器,
4.接受數(shù)據(jù):接受服務器返回數(shù)據(jù):響應頭和body
5.斷開鏈接:四次揮手斷開鏈接

OkHttp庫實現(xiàn)了哪些網(wǎng)絡請求過程的狀態(tài)回調
來一張官方的圖

OkhttpClient的Builder類可以調用eventListener設置EventListener,EventListener會進行回調如上圖的各個事件節(jié)點。

所有方法為:

public abstract class EventListener {
    public void callStart(Call call) {}
    // 域名解析
    public void dnsStart(Call call, String domainName) {}
    public void dnsEnd(Call call, String domainName, List<InetAddress> inetAddressList) {}
    // 開始連接
    public void connectStart(call, route.socketAddress(), proxy){}
    // 釋放當前Transmitter的RealConnection
    public void connectionReleased(Call call, Connection connection) {}
    public void connectionAcquired(call, result){};
    // 請求
    public void requestHeadersStart(@NotNull Call call){}
    public void requestHeadersEnd(@NotNull Call call, @NotNull Request request) {}
    // 響應
    public void requestBodyStart(@NotNull Call call) {}
    public void requestBodyEnd(@NotNull Call call, long byteCount) {}
    // 結束
    public void callEnd(Call call) {}
    // 失敗
    public void callFailed(Call call, IOException ioe) {}
}
流程解釋:

1.callStart:一次請求開始了
2.dns:dns解析過程
3.connectStart: 開始建立連接了
4.secureConnect: 開始建立TSL安全鏈接
5.connectEnd: 鏈接建立結束:可能建立失敗,失敗后可以重試
6.requestHeaders:發(fā)送請求頭
7.requestBody:發(fā)送請求body

8.responseHeaders:客戶端接受響應頭
9.responseBody:客戶端接受響應body
10.connectionReleased:鏈接釋放
11.callEnd:一次請求結束

添加日志攔截器獲取請求體、響應體大小和響應內容:
class LoggingInterceptor : Interceptor {
    private val byteCount = 1024 * 1024

    @Throws(IOException::class)
    override fun intercept(chain: Interceptor.Chain): Response {
        //chain里面包含了request和response,按需獲取

        val request = chain.request()
        val response = chain.proceed(request)

        Log.v(HTTP, "(請求地址): ${request.url()}")
        Log.v(HTTP, "請求方式: ${request.method()}")

        if (request.body() == null) {
            Log.v(HTTP, "(請求體大小): 0")
        } else {
            val requestBody = request.body()
            Log.v(HTTP, "(請求體大小): ${requestBody?.contentLength()}")
        }

        val responseBody = response.peekBody(byteCount.toLong())

        Log.v(HTTP, "(響應體大小): ${responseBody.contentLength()}")
        Log.v(HTTP, "響應內容: ${responseBody.string()}")
        return response
    }
}

自定義EventListener獲取各個數(shù)據(jù):

import android.util.Log
import com.apus.networkmonitor.constants.Tags
import okhttp3.*
import java.io.IOException
import java.net.InetAddress
import java.net.InetSocketAddress
import java.net.Proxy
import java.util.concurrent.TimeUnit

/**
 * @author: libo
 * @date: 2023/4/26 09:38
 * @Description: 監(jiān)聽okhttp請求,包括連接總時長和請求總時長
 */
open class CustomOkEventListener: EventListener() {
    private var dnsStart: Long = 0 //dns開始解析時間
    private var connectStart: Long = 0  //開始連接時間
    private var callStart: Long = 0  //開始請求時間
    private var connectAquire: Long = 0  //連接獲取時間

    override fun callStart(call: Call) {
        Log.v(Tags.CALL, "callStart")

        callStart = System.nanoTime()
    }

    override fun dnsStart(call: Call, domainName: String) {
        Log.v(Tags.CALL, "dnsStart")

        dnsStart = System.nanoTime()
    }

    override fun dnsEnd(call: Call, domainName: String, inetAddressList: MutableList<InetAddress>) {
        Log.v(Tags.CALL, "dnsEnd")

        var dnsEnd = System.nanoTime()
        var duration = TimeUnit.NANOSECONDS.toMillis(dnsEnd - dnsStart)
        Log.v(Tags.HTTP, "(域名解析時長): $duration ms")
    }

    override fun connectStart(call: Call, inetSocketAddress: InetSocketAddress, proxy: Proxy) {
        Log.v(Tags.CALL, "connectStart")

        connectStart = System.nanoTime()
    }

    override fun connectEnd(
        call: Call,
        inetSocketAddress: InetSocketAddress,
        proxy: Proxy,
        protocol: Protocol?
    ) {
        Log.v(Tags.CALL, "connectEnd")

        connectAquire = System.nanoTime()
        var duration = TimeUnit.NANOSECONDS.toMillis(connectAquire - connectStart)
        Log.v(Tags.HTTP, "(建連時長): $duration ms")
    }

    override fun connectionAcquired(call: Call, connection: Connection) {
        Log.v(Tags.CALL, "connectionAcquired")
    }

    override fun connectionReleased(call: Call, connection: Connection) {
        Log.v(Tags.CALL, "connectionReleased")

        var connectReleased = System.nanoTime()
        var duration = TimeUnit.NANOSECONDS.toMillis(connectReleased - connectAquire)
        Log.v(Tags.HTTP, "(連接保持時長): $duration ms")
    }

    override fun callEnd(call: Call) {
        Log.v(Tags.CALL, "callEnd")

        var callEnd = System.nanoTime()
        var duration = TimeUnit.NANOSECONDS.toMillis(callEnd - callStart)
        Log.v(Tags.HTTP, "(請求總時長): $duration ms")
    }

    override fun callFailed(call: Call, ioe: IOException) {
        Log.v(Tags.CALL, "callFailed")

        var callEnd = System.nanoTime()
        var duration = TimeUnit.NANOSECONDS.toMillis(callEnd - callStart)
        Log.v(Tags.HTTP, "(請求總時長): $duration ms")
    }
}

時間的計算用的是System.nanoTime(),返回正在運行的Java虛擬機的高分辨率時間源的當前值,單位為納秒。

最后,將CustomOkEventListener設置給okhttpClient:

val builder = OkHttpClient.Builder()
                .retryOnConnectionFailure(true) //失敗重連
                .addInterceptor(LoggingInterceptor()) //日志攔截器
                .eventListener(CustomOkEventListener()) //統(tǒng)計請求鏈路各時長
                builder.build()

Dns解析時長或者自定義Dns,然后設置給okhttpclient:

class CustomDns: Dns {

    override fun lookup(hostname: String?): MutableList<InetAddress> {
        var start = System.nanoTime()  //返回正在運行的Java虛擬機的當前值,高分辨率時間源,單位為納秒
        val lookup = Dns.SYSTEM.lookup(hostname)  //操作系統(tǒng)查找域名
        var end = System.nanoTime()
        var duration = TimeUnit.NANOSECONDS.toMillis(end - start)
        Log.v(Tags.HTTP, "dns_time_l(域名解析時長): $duration " + "ms")
        return lookup
    }
}
打印統(tǒng)計結果:
參考:

Okhttp官網(wǎng):https://square.github.io/okhttp/features/events/
https://juejin.cn/post/6875626117265358855

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容