请求和响应流程

见图。


所有的流程是这个时序图。
整个流程处理的网络链接和通信是在ConnectInterceptor & CallInterceptor来进行的。

其中interceptors和netinterceptors是user自定义的拦截器。

interceptor

自定义的拦截器。但是这里的和view的事件分发事件里的拦截器略有区别。
这里不是真正的拦截,因为拦截会打断整个网络请求的流程,所以给予user一个处理事物的入口。
常见的拦截器配置如下

日志拦截器

override fun intercept(chain: Interceptor.Chain): Response {
        val TAG = "OKHttp"
        val request = chain.request()
        BaseLog.i(TAG+request.hashCode(),":${request.url}")

        val headers = request.headers
        for(i in 0 until headers.size){
            var name = headers.name(i)
            if (name == "timestamp" || name == "sign" || name == "openid") {
                continue
            }
            if (!"Content-Type".equals(name, ignoreCase = true) && !"Content-Length".equals(name, ignoreCase = true)) {
                BaseLog.i(TAG + request.hashCode(), name + ": " + headers.value(i))
            }
        }

        var requestBody = request.body
        requestBody?.let {
            var buffer = Buffer()
            if(isPlaintext(buffer)){
                try {
                    requestBody.writeTo(buffer)
                } catch (e: IOException) {
                    e.printStackTrace()
                }
                val contentType = requestBody.contentType()
                if (contentType != null) {
                    val charset =
                        contentType.charset(Charset.forName("UTF-8"))
                    if (charset != null) {
                        BaseLog.i(
                            TAG + request.hashCode(),
                            "requestBody: " + buffer.readString(charset)
                        )
                    }
                }
            }
        }

        val response = chain.proceed(request)
        var responseBody = response.peekBody(1024*1024)
        BaseLog.i(TAG + request.hashCode(), "responseBody: ${responseBody.string()}")

        return response
    }

    private fun isPlaintext(buffer: Buffer): Boolean {
        return try {
            val prefix = Buffer()
            val byteCount = if (buffer.size < 64) buffer.size else 64
            buffer.copyTo(prefix, 0, byteCount)
            for (i in 0..15) {
                if (prefix.exhausted()) {
                    break
                }
                val codePoint = prefix.readUtf8CodePoint()
                if (Character.isISOControl(codePoint) && !Character.isWhitespace(
                        codePoint
                    )
                ) {
                    return false
                }
            }
            true
        } catch (e: EOFException) {
            false // Truncated UTF-8 sequence.
        }
    }

header处理

    override fun intercept(chain: Interceptor.Chain): Response {
        val request =  chain.request()
        val builder = request.newBuilder()
        builder.addHeader("Content-type", "application/json; charset=utf-8")
            .addHeader("Accept", "application/json")
            .addHeader("os", "Android")
        return chain.proceed(request)
    }

RetryInterceptor

重试,这个retry和RetryAndFollowUpInterceptor不是一个东西。那个是重定向interceptor

    private var retryNum = 0;

    override fun intercept(chain: Interceptor.Chain): Response {
        var request = chain.request()
        BaseLog.d("retryNum:$retryNum")
        var response = chain.proceed(request)
        while (!response.isSuccessful && retryNum<maxRetry){
            retryNum++
            BaseLog.d("retryNum:$retryNum")
            response = chain.proceed(request)
        }
        return response
    }

netInterceptors

这个设计,是因为interceptors是网路链接之前的数据,这个阶段是拿不到网络请求的相关资料,比如请求端口。

获取本地请求ip&端口

通过android自带的ipaddress是拿不到这个port字段的,通过分析源码,OkHttp是通过Socket链接的,这个是可以拿到port的。

override fun intercept(chain: Interceptor.Chain): Response {
        val request =  chain.request()
        try {
            val realChain = chain as RealInterceptorChain
            val realConnect = realChain.exchange().connection()
            val socket = realConnect?.socket()
            socket?.let {
                AppLog.i("local address:${socket.localAddress.hostAddress},local port:${socket.localPort}")
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }

        return chain.proceed(request)
    }

发表评论

电子邮件地址不会被公开。 必填项已用*标注