Android network request, all-round elegant analysis

Basic flow of network requests

The general process of the network request steps (the user enters a URL to the webpage and finally displays it to the user) is summarized as follows:

  • Enter the web address URL in the client browser.
  • Send it to DNS (Domain Name Server) to obtain the IP address of the WEB server corresponding to the domain name.
  • The client browser establishes a TCP (Transmission Control Protocol) connection with the WEB server.
  • The client browser sends a corresponding HTTP or HTTPS request to the WEB server corresponding to the IP address.
  • The WEB server responds to the request and returns the specified URL data or error information; if redirection is set, it is redirected to the new URL address.
  • The client browser downloads the data, parses the HTML source file, implements page typesetting during the parsing process, and displays the basic page in the browser after the parsing is completed.
  • Analyze the hyperlinks in the page, display them on the current page, repeat the above process until no hyperlinks need to be sent, and complete the display of all pages.

1. Enter the address

When we start to enter the URL in the browser, the browser is already intelligently matching the possible URL. It will find the URL that may correspond to the input string from the history, bookmarks, etc., and then give Smart prompts allow you to complete url addresses. For Google's chrome browser, it will even display the webpage directly from the cache, that is to say, the page will come out before you press enter.

2. The browser looks up the IP address of the domain name

  1. Once the request is initiated, the first thing the browser will do is to resolve the domain name. Generally speaking, the browser will first check the hosts file on the local hard disk to see if there are any rules corresponding to the domain name. If so, use it directly The ip address in the hosts file.
  2. If the corresponding ip address cannot be found in the local hosts file, the browser will send a DNS request to the local DNS server. The local DNS server is generally provided by your network access server provider, such as China Telecom and China Mobile.
  3. After the DNS request for the URL you entered reaches the local DNS server, the local DNS server will first query its cache record. If there is such a record in the cache, it can directly return the result. This process is a recursive query. If not, the local DNS server will also query the DNS root server.
  4. The root DNS server does not record the correspondence between specific domain names and IP addresses, but tells the local DNS server that you can go to the domain server to continue querying and give the address of the domain server. This process is an iterative process.
  5. The local DNS server proceeds to make a request to the domain server, in this example, to the .com domain server. After the .com domain server receives the request, it will not directly return the corresponding relationship between the domain name and the IP address, but will tell the local DNS server the address of the resolution server of your domain name.
  6. Finally, the local DNS server sends a request to the resolution server of the domain name. At this time, a corresponding relationship between the domain name and the IP address can be received. The local DNS server not only returns the IP address to the user computer, but also saves the corresponding relationship in the cache , so that when other users query next time, the results can be returned directly to speed up network access.

Introduction to HttpURLconnection

Network request is one of the most commonly used operations in Android development. The Android SDK also provides good support for HTTP (Hypertext Transfer Protocol), which includes two interfaces:

  • Standard Java interface (java.NET) ——HttpURLConnection, which can realize simple URL-based request and response functions;
  • Apache interface (org.appache.http)——HttpClient, which is more powerful in use.

But in the SDK of android API23, Google removed HttpClient. Google recommends using httpURLconnection for network access operations.

HttpURLconnection is based on the http protocol and supports various request methods such as get, post, put, and delete. The most commonly used ones are get and post. The following two request methods are explained.

How to use the Get request

HttpURLconnection is a synchronous request, so it must be placed in a child thread. An example of use is as follows:

new Thread(new Runnable() {
    @Override
    public void run() {
        try {
            String url = "https://www.baidu.com/";
            URL url = new URL(url);
            //得到connection对象。
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            //设置请求方式
            connection.setRequestMethod("GET");
            //连接
            connection.connect();
            //得到响应码
            int responseCode = connection.getResponseCode();
            if(responseCode == HttpURLConnection.HTTP_OK){
                //得到响应流
                InputStream inputStream = connection.getInputStream();
                //将响应流转换成字符串
                String result = is2String(inputStream);//将流转换为字符串。
                Log.d("kwwl","result============="+result);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}).start();
123456789101112131415161718192021222324252627

The method of using the get request is as above. If you need to pass parameters, you can directly splice the parameters after the url, and the others are exactly the same, as follows:

String url = "https://www.baidu.com/?userName=zhangsan&password=123456";
1

Points to note: 1. Use between url and parameters? separated. 2. In the key-value pair, the key and the value are connected with =. 3. Use & to connect the two key-value pairs.

Analysis: 1. Use connection.setRequestMethod("GET"); to set the request method. 2. Use connection.connect(); to connect to the network. In the request line, the setting of the request header must be placed before the network connection. 3. connection.getInputStream() just gets a stream object, not data, but we can read data from the stream, and the operation of reading data from the stream must be placed in the child thread. 4. connection.getInputStream() gets a stream object, from which data can only be read once, and empty data will be obtained when reading for the second time.

How to use Post request

The basic usage of post is as follows:

An example of use is as follows:

new Thread(new Runnable() {
    @Override
    public void run() {
        try {
            URL url = new URL(getUrl);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("POST");//设置请求方式为POST
            connection.setDoOutput(true);//允许写出
            connection.setDoInput(true);//允许读入
            connection.setUseCaches(false);//不使用缓存
            connection.connect();//连接
            int responseCode = connection.getResponseCode();
            if(responseCode == HttpURLConnection.HTTP_OK){
                InputStream inputStream = connection.getInputStream();
                String result = is2String(inputStream);//将流转换为字符串。
                Log.d("kwwl","result============="+result);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}).start();
1234567891011121314151617181920212223

Note: There are many similarities between post request and get request, except that there are some more settings before connecting, and the two can be compared and used for learning.

Use the post request to pass key-value pair parameters

new Thread(new Runnable() {
    @Override
    public void run() {
        try {
            URL url = new URL(getUrl);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("POST"); 
            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.setUseCaches(false);
            connection.connect();
            String body = "userName=zhangsan&password=123456";
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(connection.getOutputStream(), "UTF-8"));
            writer.write(body);
            writer.close();
            int responseCode = connection.getResponseCode();
            if(responseCode == HttpURLConnection.HTTP_OK){
                InputStream inputStream = connection.getInputStream();
                String result = is2String(inputStream);//将流转换为字符串。
                Log.d("kwwl","result============="+result);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}).start();
1234567891011121314151617181920212223242526272829

analyze:

  1. The essence of passing parameters in the post method is: get an output stream from the connection, and write data to the server through the output stream.
  2. The splicing of data adopts the key-value pair format, and the key and value are connected by =. Each key-value pair is connected with &.

Use post request to pass json format parameters

The post request can also pass parameters in json format, the usage example is as follows:

new Thread(new Runnable() {
    @Override
    public void run() {
        try {
            URL url = new URL(getUrl);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("POST"); 
            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.setUseCaches(false);
            connection.setRequestProperty("Content-Type", "application/json;charset=utf-8");//设置参数类型是json格式
            connection.connect();
            String body = "{userName:zhangsan,password:123456}";
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(connection.getOutputStream(), "UTF-8"));
            writer.write(body);
            writer.close();
            int responseCode = connection.getResponseCode();
            if(responseCode == HttpURLConnection.HTTP_OK){
                InputStream inputStream = connection.getInputStream();
                String result = is2String(inputStream);//将流转换为字符串。
                Log.d("kwwl","result============="+result);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}).start();
123456789101112131415161718192021222324252627282930

There are two differences between passing parameters in json format and passing key-value pair parameters:

  1. When passing data in json format, you need to set the parameter type in the request header to json format.
  2. body is a string in json format.

set request header

Both the Get request and the post request can set the request header, and the method of setting the request header is the same. In order to save space, the repeated code is no longer listed, the core code is as follows:

connection.setRequestMethod("POST");
connection.setRequestProperty("version", "1.2.3");//设置请求头
connection.setRequestProperty("token", token);//设置请求头
connection.connect();
1234

Advantages of OkHttp

In terms of network optimization:

  • Built-in connection pool, support connection multiplexing;
  • Support gzip compressed response body;
  • Avoid duplicate requests through caching;
  • Support http2, all requests to a machine share the same socket.

Functional aspects:

Full-featured, meeting most of the needs of network requests

In terms of scalability:

The Chain of Responsibility pattern makes it easy to add a custom interceptor to process requests and return results

principle

work process:

  • Create a Call through OkhttpClient and initiate a synchronous or asynchronous request;
  • okhttp will manage all our RealCall (the specific implementation class of Call) through Dispatcher, and process synchronous or asynchronous requests through execute() and enqueue() methods;
  • The execute() and enqueue() methods will finally call the getResponseWithInterceptorChain() (key) method in RealCall to obtain the return result from the interceptor chain;
  • In the interceptor chain, requests are processed sequentially through RetryAndFollowUpInterceptor (redirection interceptor), BridgeInterceptor (bridge interceptor), CacheInterceptor (cache interceptor), ConnectInterceptor (connection interceptor), and CallServerInterceptor (network interceptor), and the service After the connection is established, the returned data is obtained, and after being processed by the above interceptors, the result is finally returned to the caller.

Schematic:

edit

Add picture annotations, no more than 140 words (optional)

use

1. okhttp initialization

 Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() {
     @Override public Response intercept(Chain chain) throws IOException {
         Response originalResponse = chain.proceed(chain.request());
         return originalResponse.newBuilder()
                 .removeHeader("Pragma")
                 .header("Cache-Control", String.format("max-age=%d", 60))
                 .build();
     }
 };
 mOkHttpClient.setConnectTimeout(15000, TimeUnit.SECONDS);
 mOkHttpClient.setReadTimeout(15000, TimeUnit.SECONDS);
 mOkHttpClient.setWriteTimeout(15000, TimeUnit.SECONDS);
 mOkHttpClient.setRetryOnConnectionFailure(true);
 //-------------------------------设置http缓存,提升用户体验-----------------------------------
 Cache cache;
 File httpCacheDirectory =  StorageUtils.getOwnCacheDirectory(context,HTTP_CACHE_FILENAME);
 cache = new Cache(httpCacheDirectory, 10 * 1024);
 mOkHttpClient.setCache(cache);
 mOkHttpClient.networkInterceptors().add(REWRITE_CACHE_CONTROL_INTERCEPTOR);
 //-------------------------------设置http缓存,提升用户体验-----------------------------------
// Handler mDelivery = new Handler(Looper.getMainLooper());
 if (false) {
     mOkHttpClient.setHostnameVerifier(new HostnameVerifier() {
         @Override
         public boolean verify(String hostname, SSLSession session) {
             return true;
         }
     });
 }

2.Get application data

Request request = new Request.Builder()
        .url("网络地址这里面设置一个传参数如何办")
        .addHeader("Accept", "application/json; q=0.5").build();
上面代码看到url缺么有带post,这就是get,我当时看到这个半天还在想这就是Get,至少带get的字样,缺么有,这就是Get,然后这
里面涉及的一个参数如何传。会有两个问题参数如何传、如果是apache的,如何转到okhttps,后面都会在我的github会封装一个库。
<span style="white-space:pre">  </span>FormEncodingBuilder body = new FormEncodingBuilder();
        for (ConcurrentHashMap.Entry<String, String> entry : params.urlParams.entrySet()) {
            body.addEncoded(entry.getKey(), entry.getValue());
        }
        Request request = new Request.Builder()
                .url(getUrlWithQueryString(true, params.url, params))
                .build();
        try {
            BaseOkHandler handler = new BaseOkHandler(callback, params);
            client.newCall(request).enqueue(handler);
        } catch (Exception e) {
            e.printStackTrace();
        }
上面看到的params就相当于apache中的RequestParams类,里面传入参数就可以,借鉴的并做修改后得到。
 getUrlWithQueryString(boolean shouldEncodeUrl, String url, BaseParams params) {
        if (url == null)
            return null;
        if (shouldEncodeUrl) {
            try {
                String decodedURL = URLDecoder.decode(url, "UTF-8");
                URL _url = new URL(decodedURL);
                URI _uri = new URI(_url.getProtocol(), _url.getUserInfo(), _url.getHost(), _url.getPort(), _url.getPath(),
 _url.getQuery(), _url.getRef());
                url = _uri.toASCIIString();
            } catch (Exception ex) {
                // Should not really happen, added just for sake of validity
            }
        }
        if (params != null) {
            // Construct the query string and trim it, in case it
            // includes any excessive white spaces.
            String paramString = params.getParamString().trim();
            // Only add the query string if it isn't empty and it
            // isn't equal to '?'.
            if (!paramString.equals("") && !paramString.equals("?")) {
                url += url.contains("?") ? "&" : "?";
                url += paramString;
            }
        }
     
        return url;
    }

And this function is to format and concatenate all parameters into a string.

3. Post application data

 Request request = new Request.Builder()
      .url(url)
      .post(body)//post是关键,提交表单数据、这里面有封装好多库。
      .build();
      Response response = client.newCall(request).execute();

4.Post submit file

 MultipartBuilder builder = new MultipartBuilder().type(MultipartBuilder.FORM);
        if (params.fileParams.size() > 0) {
            RequestBody fileBody = null;
       for (ConcurrentHashMap.Entry<String, BaseParams.FileWrapper> entry1 : params.fileParams.entrySet()) {
                {
                    File file = entry1.getValue().file;
                    String fileName = file.getName();
                    fileBody = RequestBody.create(MediaType.parse(guessMimeType(fileName)), file);
                    //TODO 根据文件名设置contentType
                    builder.addPart(Headers.of("Content-Disposition",
                                "form-data; name="" + entry1.getKey() + ""; filename="" + fileName + """),
                            fileBody);
                }
            }
        }
        Request request = new Request.Builder()
                .url(params.url)
                .post(builder.build())
                .build();

As you can see, you only need to use the MultipartBuilder class form to upload files.

5. Message back processing

public class BaseOkHandler implements Callback {
    private HttpCallback callBack;
    BaseParams param;
     
    public BaseOkHandler(HttpCallback response, BaseParams cacheParams) {
        this.callBack = response;
        param = cacheParams;
    }
     
    @Override
    public void onFailure(Request request, IOException e) {
    }
     
    @Override
    public void onResponse(Response response) throws IOException {
        try {
            if (response.isSuccessful()) {
                //成功得到文本信息
                String content = response.body().string();
                //通过Handler来传给UI线程。
                Message msg =new Message();
                msg.obj = content;
                msg.what=0;
                mHandler.sendMessage(msg);
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
     
    Handler mHandler = new Handler() {
     
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 0:
                    //得到数据并去做解析类。
     BaseEntity entity = JsonPaserFactory.paserObj(msg.obj.toString(), param.paserType);
                    //通知UI界面
    callBack.onSuccess(msg.obj.toString(), entity, param.paserType);
                    break;
                default:
                    break;
            }
        }
     
    };
}

This article mainly explains the network request technology in Android development and development. For more information about Android network technology, please refer to the "Android Core Technology Manual", which records 1000 technical points on most Android skills. Click to view the detailed categories.

Guess you like

Origin blog.csdn.net/m0_70748845/article/details/132543738