The whole process

  • Create an OKhttpClient, request client class, and store it as a global instance of the singleton used for global network requests
  • Create a Request object that encapsulates the Request message information, including the URL, path, Request methods GET/POST, Request parameters, and Request headers. Inside the Request object is generated by the build chain
  • The Call object is obtained by calling the newCall method called by Request. In OKHTTP, the implementation class of Call is RealCall, through which subsequent asynchronous synchronous network request operations can be performed
  • Asynchronous synchronization is determined by the Dispatcher Dispatcher, which maintains an internal thread pool for network requests that realCall adds to the Dispatcher, which has three queues for synchronous asynchronous requests
  • Whether synchronous or asynchronous, the real server data retrieval is done internally by interceptors in Okhttp, which build a chain of interceptors and execute each interceptor in turn to return server data. The main interceptors include
    • RetryAndFollow: Retries and redirects requests directly after failures
    • Bridge: Sets content length, content encoding, gZIP compression, cookie headers, etc., mainly pre-request operations
    • Cache: Manages the Cache. If a Cache meets the requirements, the Cache is returned directly without passing through the network
    • Connect: Find the appropriate connection for the current request. Note that existing connections may be reused here
    • CallServer: initiates a real access request to the server and receives data returned by the server
  • As shown in figure

Synchronous and asynchronous requests

A synchronous request

  1. Create OkHttpClient and Request objects: Create the OkHttpClient object and Request object with build
  2. Encapsulate Request as a Call object: Build a Request object, and build a Call object from OkHttpClient and the Request object
  3. Call execute() to send a synchronization request

Note: After sending a synchronous request, it is blocked until a response is received.

An asynchronous request

  1. Create OkHttpClient and Request objects
  2. Encapsulate Request as a Call object
  3. The enQueue that calls the Call sends synchronous requests and does the corresponding data processing in onFailure and onResponse callbacks

Note: Both onFailure and onResponse are executed in the worker thread (child thread)

Summary of the enqueue method

  • Determine the current call
  • Encapsulate an AsyncCall object
  • client.dispatcher().enqueue()

Difference from synchronous request

  • Method calls that initiate requests: synchronous execute and asynchronous enQueue
  • Thread blocking or not: Synchronous blocking asynchronous not blocking

The following code

    val url = "https://api.github.com/users/dsh/repos"
    val hostname = "api.github.com"

    val client = OkHttpClient.Builder()
      .build()
    val request: Request = Request.Builder()
      .url(url)
      .build()
    client.newCall(request)
      .enqueue(object : Callback {
        override fun onFailure(call: Call, e: IOException) {
          e.printStackTrace()
        }

        override fun onResponse(call: Call, response: Response) {
          println("Response status code: ${response.code()}")
        }
      })
Copy the code

The task scheduling core class Dispatcher

Q1.okhttp How to implement synchronous asynchronous requests? Both synchronous and asynchronous requests sent are managed in the Dispatcher for their status

The role of dispatcher is to maintain the status of requests and to maintain a pool of threads for executing requests.

Q3. Why do asynchronous requests need two queues

  • The Dispatcher producers
  • The ExecutorService consumer pool
  • A Deque cache
  • Deque running tasks

Several key variables of the DispatcherA diagram of the Dispatcher’s dispatch process

OKHttp interceptor stream

Interceptors are a powerful mechanism provided in OkHttp that enables network listening, request and response rewriting, and retry of failed requests

OkHttp mainly has network interceptors and application interceptors, as shown in figure, we are mainly concerned with application interceptorsOkhttp’s main interceptors

Core logic:

  1. The request is processed before the request is initiated
  2. Call the next interceptor and get response
  3. Response is processed and returned to the previous interceptor

The synchronous request method execute is used as an example, as shown in the figure

  • ① Create a list of interceptors and place them in a list of interceptors

  • Create a ReallnterceptorChain and proceed to the chain

  • ③ The proceed method creates and calls the next interceptor, retrieving the response

  • ④ Each interceptor processes the response and returns it to the previous interceptor

RetryAndFollowUpInterceptor retry to redirect the interceptor

It is mainly responsible for failed reconnection. Not all network requests can be reconnected after they fail, but there are certain limits. Okhttp will help us detect network anomalies and judge response codes

  • Call ReallnterceptorChain. Proceed (…). Making network requests
  • Determine whether to request again based on the abnormal result or response result
  • Calls the next interceptor, processes the response, and returns it to the previous interceptor
@Override public Response intercept(Chain chain) throws IOException { ... // Reconnection is not unlimited, more than 20 reconnection requests, If (++followUpCount > MAX_FOLLOW_UPS) {throw new ProtocolException("Too many follow-up requests: " + followUpCount); }... }Copy the code

BridgeInterceptor BridgeInterceptor

It is mainly responsible for adding request header information, including content length, encoding method, compression, etc. KeepAlive is the basis of connection reuse.

The working process

  • 1. Is responsible for converting a Request constructed by users into a Request capable of network access

  • 2. Send the Request that meets the network Request to the network

  • 3. Convert the Response returned from the network request into the Response available to the user.

CacheInterceptor a CacheInterceptor

Caches put and GET methods

Put method

The get method

Cache interceptor operations

ConnectInterceptor

Connection pooling ConnectionPool

  • Each HTTP request produces a Transmitter object

  • The weak reference to the Transmitter object is added to the CCD collection of the RealConnection object

  • From the connection pool

ConnectionPool recycling:

  1. OKHttp uses a GC collection algorithm
  2. The number of transmitters will gradually become zero
  3. Monitored and reclaimed by the thread pool so that multiple healthy keep-alive connections can be maintained

CallServerInterceptor

  • Make a real network request
  • Receive the response from the server

It mainly includes the following steps:

  1. Write request header
  2. Write request body
  3. Build the response header
  4. Building response body
  5. Return response response
public final class CallServerInterceptor implements Interceptor { private final boolean forWebSocket; public CallServerInterceptor(boolean forWebSocket) { this.forWebSocket = forWebSocket; } @Override public Response intercept(Chain chain) throws IOException { RealInterceptorChain realChain = (RealInterceptorChain) chain; Exchange exchange = realChain.exchange(); Request request = realChain.request(); long sentRequestMillis = System.currentTimeMillis(); / / 1. Written request to the header exchange. WriteRequestHeaders (request); boolean responseHeadersStarted = false; Response.Builder responseBuilder = null; if (HttpMethod.permitsRequestBody(request.method()) && request.body() ! = null) {// If Expect of the request header is 100-continue, If ("100-continue".equalsignorecase (request.header("Expect"))) {exchange.flushRequest(); responseHeadersStarted = true; exchange.responseHeadersStart(); responseBuilder = exchange.readResponseHeaders(true); {responseBuilder == null) {responseBuilder == null) {responseBuilder == null) {responseBuilder == null) {responseBuilder == null) {responseBuilder == null) {responseBuilder == null; BufferedSink bufferedRequestBody = Okio.buffer( exchange.createRequestBody(request, true)); request.body().writeTo(bufferedRequestBody); } else {// If 100-continue, Write the body BufferedSink bufferedRequestBody = Okio. Buffer (exchange. CreateRequestBody (request, false)); request.body().writeTo(bufferedRequestBody); bufferedRequestBody.close(); } } else { exchange.noRequestBody(); if (! exchange.connection().isMultiplexed()) { exchange.noNewExchangesOnConnection(); } } } else { exchange.noRequestBody(); } / / end request if (the request body () = = null | |! request.body().isDuplex()) { exchange.finishRequest(); } if (! responseHeadersStarted) { exchange.responseHeadersStart(); } / / read / / build the response body network response header information of the if (responseBuilder = = null) {responseBuilder = exchange. ReadResponseHeaders (false); } Response response = responseBuilder .request(request) .handshake(exchange.connection().handshake()) .sentRequestAtMillis(sentRequestMillis) .receivedResponseAtMillis(System.currentTimeMillis()) .build(); int code = response.code(); if (code == 100) { response = exchange.readResponseHeaders(false) .request(request) .handshake(exchange.connection().handshake()) .sentRequestAtMillis(sentRequestMillis) .receivedResponseAtMillis(System.currentTimeMillis()) .build(); code = response.code(); } exchange.responseHeadersEnd(response); If (forWebSocket && code == 101) {response = response.newBuilder().body(util.empty_response).build(); } else { response = response.newBuilder() .body(exchange.openResponseBody(response)) .build(); } if ("close".equalsIgnoreCase(response.request().header("Connection")) || "close".equalsIgnoreCase(response.header("Connection"))) { exchange.noNewExchangesOnConnection(); } if ((code == 204 || code == 205) && response.body().contentLength() > 0) { throw new ProtocolException( "HTTP " + code  + " had non-zero Content-Length: " + response.body().contentLength()); } return response; }}Copy the code

The outline of a network request in Okhttp

  1. Encapsulate the Call object request
  2. Dispatcher distribution of requests
  3. GetResponseWithInterceptors () method

The interview related

1. Android basic network programming: Socket, HttpClient and HttpURLConnection

  • Socket
    • Is a programming call interface that encapsulates THE TCP /IP protocol
    • Occurs in pairs, a pair of sockets: includes IP address and port number
  • The Socket with Http
    • Http: request-response mode. HTTP belongs to the application layer
    • Socket: The server actively sends data. The Socket belongs to the transport layer
  • HttpClient
    • It has been removed since 6.0
  • HttpURLConnection
    class HttpConnectionTest { public void HttpConnectionGet() throws IOException { String getURL = "GET_URL" + " ? username= " + URLEncoder.encode(" fat man ", "utf-8"); URL getUrl = new URL(getURL); HttpURLConnection connection = (HttpURLConnection)getUrl.openConnection(); connection.connect(); // Get the input stream, And read it with a Reader, that's when you actually send the request to the server. BufferedReader Reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); System.out.println(" ======== "); System.out.println(" Contents of get request "); System.out.println(" ======== "); String lines; while((lines = reader.readLine())! = null){ System.out.println(lines); } reader.close(); Connection.disconnect (); // Disconnect the socket. System.out.println(" ======== "); System.out.println(" Contents of get request ends "); System.out.println(" ======== "); }}Copy the code

2. Do you know websocket? Do you know the difference between socket and socket? How does OkHTTP handle websocket issues?

  • NewWebSocket (Request,listener) establishes a socket to establish a connection
  • Listen for and send messages in the Listener
  • Remember to call shutdown() to close the socket connection
    public void OkhttpSocketTest(){ OkHttpClient client = new OkHttpClient.Builder().build(); Request request = new Request.Builder().url("www.webSocket.com").build(); WebSocketListener listener = new WebSocketListener() { @Override public void onOpen(@NotNull WebSocket webSocket, @NotNull Response response) { super.onOpen(webSocket, response); webSocket.send("hello"); webSocket.send(ByteString.decodeHex("absd")); webSocket.close(1000,"bye"); } @Override public void onMessage(@NotNull WebSocket webSocket, @NotNull String text) { super.onMessage(webSocket, text); // To interact with the UI, use hander setText("onMessage: "+ bytes); handler.sendEmptyMessage(0); } @Override public void onMessage(@NotNull WebSocket webSocket, @NotNull ByteString bytes) { super.onMessage(webSocket, bytes); setText("onMessage byteString: " + bytes); handler.sendEmptyMessage(0); } @Override public void onFailure(@NotNull WebSocket webSocket, @NotNull Throwable t, @Nullable Response response) { super.onFailure(webSocket, t, response); setText("onFailure:"+ t.getMessage()); } @Override public void onClosing(@NotNull WebSocket webSocket, int code, @NotNull String reason) { super.onClosing(webSocket, code, reason); webSocket.close(1000, null); setText("onClosing:"+ code + "/" + reason); } @Override public void onClosed(@NotNull WebSocket webSocket, int code, @NotNull String reason) { super.onClosed(webSocket, code, reason); setText("onClosed:"+ code + "/" + reason); }}; client.newWebSocket(request,listener); client.dispatcher().executorService().shutdown(); }Copy the code

3. WebSocker& Polling related

  • Polling is when the browser makes an HTTP request to the server at a specific time interval, and the server returns the latest data to the client’s browser.
  • Short polling: The Client sends requests to the server at intervals and receives responses from the server
    • Disadvantages: In a certain period of time, the server does not update the data, but the client still sends requests to query at intervals, so the query during this period is invalid redundant data, wasting bandwidth (such as live comments short polling, always request the first page of data, return a large number of repeated data).
  • Long polling: After receiving a request, the server does not immediately return a response, but only returns a response when the data is updated. If no data is updated, the request is kept connected
  • Disadvantages of polling:
    • Wasted bandwidth (HTTP heads are large and have less valid information)
    • Consumes server CPU usage
  • WebSocket communication model
  • WebSocket is different from Http
    • A network protocol equivalent to Http
    • Two-way communication protocol
  • Websockets have nothing to do with sockets
    • Socket is not actually a protocol
    • WebSocket is a protocol
  • WebSocket summary
    • 1. It is essentially a TCP based protocol
    • 2. Send an HTTP request to the server/” Upgrade:WebSocket”
    • 3. The server parses these additional headers

4. How does Http handle caching? How does Okhttp handle cache-related issues?

  • There are two types of mandatory cache and comparison cache
  • Mandatory caching: Includes Expires and cache-control
    • Expires
      • The Expires value is the expiration time returned by the server, or if it is less than the expiration time, the cache is used
      • Http1.0 is used frequently and is deprecated based on the browser default 1.1
      • Problem: The expiration date is returned by the server
    • Cache-control (Critical)
      • Cache-control is the header added to the Response returned by the server
      • Values:
        • Private: The client can cache
        • Public: Both client and proxy servers can cache
        • Max-age: specifies the number of seconds after the cache content expires
        • No-cache: used in comparison cache
        • No-store: All content is not cached
  • Compared to the cache
    • The first thing you need to do is compare and determine if you can use caching.
    • ETag/if-none-match: pairs appear
      • Etag: A unique identifier that tells the browser that the current resource is on the server when the server responds to a request
      • If-none-match: this field is used to notify the server of the unique identifier of cached data in the client segment when the server is requested again
    • Last-Modified / If-Modified-Since
      • Last-modified: When the server responds to a request, it tells the browser when the resource was Last Modified
      • If-modified-since: This field is used to notify the server of the last modification time of the resource returned by the server during the last request
  • The cache is

5. How does breakpoint continuation work? How to do that? How are related issues implemented in OKHTTP?

  • Resumable: Downloads continue from where the file was already downloaded
  • It works by adding RANGE information to the header
  • Both create a RandomAccessFile object and call its seek method

As shown in the figure:

6. How to implement okHTTP?

  • Multithreaded download: Each thread is responsible for downloading only a portion of the file
  • TotalSize and the file size to download for each thread partSize = totalSize/threadCount
  • In each thread, the request is created and a RandomAccessFile object is created, the seek method is called to write at the specified location, and finally the IO stream is closed

Here is:

7. How do I upload files? The principle? How does OKHTTP complete file upload

  • Specify the ContentType of the Http header
  • The CONTent-type attribute specifies the HTTP Content Type of the request and response
  • In the example shown below, if the file is too long for a package to be sent, the boundry delimiter is required for fragment upload
  • In Okhttp, requests are built primarily through MultiPartBody

Here is:

8. How to parse JSON data? How does OKHTTP parse JSON data?

  • Json: Data exchange format in text format
  • Json is lighter than XML and easier to read than binary
  • Json parsing
    • Traditional jsonObject parsing
    • Gson
    • FastJson
  • Gson parsing
    Gson mGson = new Gson();
    List<User> userList = mGson.fromJson(jsonArray.toString(), new TypeToken<List<User>>(){
                        } .getType());
    Copy the code

    Way 2

    JsonParser parser = new JsonParser();
    JsonArray jsonArray = parser.parse(json1).getAsJsonArray();
    Gson gson = new Gson();
    Arraylist<UserBean> userBeanList = new Arraylist<>();
    for (JsonElement user : jsonArray) {
        UserBean userBean = gson.fromJson(user,UserBean.class);
        userBeanList.add(userBean);
    }
    Copy the code

9. How does okhttp handle HTTPS?

  • Https is an Http protocol based on SSL/TLS

  • Asymmetric vs. symmetric encryption

    • The keys used in symmetric encryption can be sent by asymmetric encryption
    • Asymmetric encryption is not as fast as symmetric encryption, so HTTPS uses symmetric encryption during actual transmission
  • Https algorithm

    • Asymmetric encryption: SSL/TLS handshake phase
    • Symmetric encryption: Encrypts transmitted data
    • Hash: Verifies the integrity of the data sent from the client to the server
  • Summary of Https communication process:

    • The server uses RSA to generate the public key and private key. The public key is stored in a certificate and sent to the client. The private key is saved by the server
    • After receiving the public key, the client first checks the validity of the certificate to an authoritative server. If the certificate is valid, the client generates a random number, which is used as the communication key, which is called the symmetric key. The client encrypts the random number with the public key and sends it to the server
    • The server uses key decryption to obtain the symmetric key, and then the two parties encrypt and decrypt the communication with the symmetric key