preface

In the previous article we have analyzed the ok to built the first of five interceptor RetryAndFollowUpInterceptor, here we are going to explore BridgeInterceptor will continue to be in accordance with the order.

introduce

Let’s start with class comments:

Bridges from application code to network code. First it builds a network request from a user request. Then it proceeds to call the network. Finally it builds a user response from the network response.



The bridge between the application layer and the network layer, which first adds some parameters required by the network layer to the request initiated by the user, then calls the network, and finally parses the result of the user’s request from the response body
  @Throws(IOException::class)
  override fun intercept(chain: Interceptor.Chain): Response {
    val userRequest = chain.request()
    val requestBuilder = userRequest.newBuilder()

    val body = userRequest.body
    if(body ! =null) {
      val contentType = body.contentType()
      if(contentType ! =null) {
        requestBuilder.header("Content-Type", contentType.toString())
      }
      val contentLength = body.contentLength()
      if(contentLength ! =- 1L) {
        requestBuilder.header("Content-Length", contentLength.toString())
        requestBuilder.removeHeader("Transfer-Encoding")}else {
        requestBuilder.header("Transfer-Encoding"."chunked")
        requestBuilder.removeHeader("Content-Length")}}if (userRequest.header("Host") = =null) {
      requestBuilder.header("Host", userRequest.url.toHostHeader())
    }

    if (userRequest.header("Connection") = =null) {
      requestBuilder.header("Connection"."Keep-Alive")}// If we add an "Accept-Encoding: gzip" header field we're responsible for also decompressing
    // the transfer stream.
    var transparentGzip = false
    if (userRequest.header("Accept-Encoding") = =null && userRequest.header("Range") = =null) {
      transparentGzip = true
      requestBuilder.header("Accept-Encoding"."gzip")}val cookies = cookieJar.loadForRequest(userRequest.url)
    if (cookies.isNotEmpty()) {
      requestBuilder.header("Cookie", cookieHeader(cookies))
    }

    if (userRequest.header("User-Agent") = =null) {
      requestBuilder.header("User-Agent", userAgent)
    }

    val networkResponse = chain.proceed(requestBuilder.build())

    cookieJar.receiveHeaders(userRequest.url, networkResponse.headers)
    
    val responseBuilder = networkResponse.newBuilder()
        .request(userRequest)
    if (transparentGzip &&
        "gzip".equals(networkResponse.header("Content-Encoding"), ignoreCase = true) &&
        networkResponse.promisesBody()) {
      val responseBody = networkResponse.body
      if(responseBody ! =null) {
        val gzipSource = GzipSource(responseBody.source())
        val strippedHeaders = networkResponse.headers.newBuilder()
            .removeAll("Content-Encoding")
            .removeAll("Content-Length")
            .build()
        responseBuilder.headers(strippedHeaders)
        val contentType = networkResponse.header("Content-Type")
        responseBuilder.body(RealResponseBody(contentType, - 1L, gzipSource.buffer()))
      }
    }
    return responseBuilder.build()
  }
Copy the code

The code for the Bridge interceptor is relatively easy to read compared to the retry interceptor from the previous article. We will divide the analysis into two stages according to interceptor calls:

The Request phase

  • Take the body contentType and put it inside the header

  • Get the length of the request body into the header

    • The header field transfer-encoding specifies the Encoding method used to transmit the main body of the message. The HTTP1.1 transport encoding is valid only for block transport encoding. A value of chunked indicates that the content size of the request body is unknown. Therefore, transfer-Encoding and Content-Length headers cannot coexist.
  • Put the requested host inside the header

    • Host is the domain name in the request and is explained in detail in HttpUrl

      URL host()
      http://android.com/ "android.com"
      http://127.0.0.1/ "127.0.0.1"
      http://[::1]/ : : "1"
      http://xn--n3h.net/ "xn--n3h.net"
    • The toHostHeader() method takes the corresponding domain name and concatenates the default HTTP port 80 and HTTPS port 443

  • Setting connection mode to keep-alive makes it easy to reuse the connection pool.

  • If the user does not set accept-encoding, then the data receipt format is specified as GZIP. Incidentally: GZIP compression can greatly reduce network traffic consumption.

  • Put cookies in the header

  • Put user-agent in the request header. If the user does not set this parameter, put the default agent:okhttp/ X.X.X

The Response phase

  • The first is to get the returned cookie based on the URL.
  • If content-Encoding is gZIP and Content-Length >0, fetch the body for processing
  • The request response body is processed once, because the body of the response body is transmitted in type GZIP and is processed through the encapsulated method class resolution
  • Parsing becomes the body that the user can actually use

conclusion

That’s it for the entire BridgeInterceptor process. There are roughly three steps

  • The request is processed again, using the user configuration if the user has set the parameters, and using the default if not.
  • Invoke the next interceptor through chain.
  • The request of the interface is processed again, such as Gzip and cookie, and finally parsed into the body that the user can actually use.

As you can see, the entire BridgeInterceptor process is quite simple. It simply encapsulates some of the required parameters of the network transport protocol, so that the application layer does not need to invoke these steps.